Author: Unreal good

Source: Hang Seng LIGHT Cloud Community

The introduction

In normal Java projects, there is too much unfriendly code: getters/setters/toStrings for POJos; Exception handling; The shutdown of I/O streams and so on, boilerplate code that was both untechnical and ugly, Lombok was born.

Lombok is already built into IDEA 2020, and SpringBoot 2.1.x and later builds Lombok into the Starter. Today let’s talk about using Lombok and see how it works!

Lombok installation configuration

Before using Lombok, you need to install it in the IDE you are using. Here, using IDEA as an example, the installation steps are very simple:

  • Go to File -> Settings -> Plugin -> Marketplace, search for Lombok and install it

  • Select Lombok as the search result and click Install to Install.

  • Restart after the installation is complete.

After the Lombok plug-in is installed in the IDE, you can add Lombok’s dependencies to the POM.xml file for use.

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
Copy the code

Lombok’s common annotations

1. @Data

@data is a handy composite annotation that combines @toString, @equalSandHashCode, @getter, @setter, and @requiredargsConstructor.

@Data
public class DemoUser {
    private String userId;
    private String userName;
    private String userAge;
}
Copy the code

Lombok generates the following code when compiled:

public class DemoUser {
    private String userId;
    private String userName;
    private String userAge;

    public DemoUser(a) {}public String getUserId(a) {
        return this.userId;
    }

    public String getUserName(a) {
        return this.userName;
    }

    public String getUserAge(a) {
        return this.userAge;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setUserAge(String userAge) {
        this.userAge = userAge;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if(! (oinstanceof DemoUser)) {
            return false;
        } else {
            DemoUser other = (DemoUser)o;
            if(! other.canEqual(this)) {
                return false;
            } else {
                label47: {
                    Object this$userId = this.getUserId();
                    Object other$userId = other.getUserId();
                    if (this$userId == null) {
                        if (other$userId == null) {
                            breaklabel47; }}else if (this$userId.equals(other$userId)) {
                        break label47;
                    }

                    return false;
                }

                Object this$userName = this.getUserName();
                Object other$userName = other.getUserName();
                if (this$userName == null) {
                    if(other$userName ! =null) {
                        return false; }}else if (!this$userName.equals(other$userName)) {
                    return false;
                }

                Object this$userAge = this.getUserAge();
                Object other$userAge = other.getUserAge();
                if (this$userAge == null) {
                    if(other$userAge ! =null) {
                        return false; }}else if (!this$userAge.equals(other$userAge)) {
                    return false;
                }

                return true; }}}protected boolean canEqual(Object other) {
        return other instanceof DemoUser;
    }

    public int hashCode(a) {
        int PRIME = true;
        int result = 1;
        Object $userId = this.getUserId();
        int result = result * 59 + ($userId == null ? 43 : $userId.hashCode());
        Object $userName = this.getUserName();
        result = result * 59 + ($userName == null ? 43 : $userName.hashCode());
        Object $userAge = this.getUserAge();
        result = result * 59 + ($userAge == null ? 43 : $userAge.hashCode());
        return result;
    }

    public String toString(a) {
        return "DemoUser(userId=" + this.getUserId() + ", userName=" + this.getUserName() + ", userAge=" + this.getUserAge() + ")"; }}Copy the code

2.@Value

Using the @Value annotation, you can declare a class immutable. When you declare a class, it is final, cannot be inherited, and its properties become final.

@Value
public class DemoUser {
    private final String userId;
    private final String userName;
    private final String userAge;
}
Copy the code

Lombok generates the following code when compiled:

public final class DemoUser {
    private final String userId;
    private final String userName;
    private final String userAge;

    public DemoUser(String userId, String userName, String userAge) {
        this.userId = userId;
        this.userName = userName;
        this.userAge = userAge;
    }

    public String getUserId(a) {
        return this.userId;
    }

    public String getUserName(a) {
        return this.userName;
    }

    public String getUserAge(a) {
        return this.userAge;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if(! (oinstanceof DemoUser)) {
            return false;
        } else {
            DemoUser other;
            label44: {
                other = (DemoUser)o;
                Object this$userId = this.getUserId();
                Object other$userId = other.getUserId();
                if (this$userId == null) {
                    if (other$userId == null) {
                        breaklabel44; }}else if (this$userId.equals(other$userId)) {
                    break label44;
                }

                return false;
            }

            Object this$userName = this.getUserName();
            Object other$userName = other.getUserName();
            if (this$userName == null) {
                if(other$userName ! =null) {
                    return false; }}else if (!this$userName.equals(other$userName)) {
                return false;
            }

            Object this$userAge = this.getUserAge();
            Object other$userAge = other.getUserAge();
            if (this$userAge == null) {
                if(other$userAge ! =null) {
                    return false; }}else if (!this$userAge.equals(other$userAge)) {
                return false;
            }

            return true; }}public int hashCode(a) {
        int PRIME = true;
        int result = 1;
        Object $userId = this.getUserId();
        int result = result * 59 + ($userId == null ? 43 : $userId.hashCode());
        Object $userName = this.getUserName();
        result = result * 59 + ($userName == null ? 43 : $userName.hashCode());
        Object $userAge = this.getUserAge();
        result = result * 59 + ($userAge == null ? 43 : $userAge.hashCode());
        return result;
    }

    public String toString(a) {
        return "DemoUser(userId=" + this.getUserId() + ", userName=" + this.getUserName() + ", userAge=" + this.getUserAge() + ")"; }}Copy the code

3.@Slf4j

When generating log objects using Lombok, there are several annotations available, depending on the logging implementation used. For example, @log, @log4j, @log4j2, @slf4j and so on.

@Value
public class DemoUser {
    private final String userId;
    private final String userName;
    private final String userAge;
}
Copy the code

Lombok generates the following code when compiled:

public class DemoUser {
    private static final Logger log = LoggerFactory.getLogger(DemoUser.class);
    private String userId;
    private String userName;
    private String userAge;

    public DemoUser(a) {}}Copy the code

4.@Builder

Using the @Builder annotation, you can create objects from Builder mode, which is called in chain mode to create objects conveniently.

@Builder
public class DemoUser {
    private final String userId;
    private final String userName;
    private final String userAge;
}
Copy the code

Lombok generates the following code when compiled:

public class DemoUser {
    private final String userId;
    private final String userName;
    private final String userAge;

    DemoUser(String userId, String userName, String userAge) {
        this.userId = userId;
        this.userName = userName;
        this.userAge = userAge;
    }

    public static DemoUser.DemoUserBuilder builder(a) {
        return new DemoUser.DemoUserBuilder();
    }

    public static class DemoUserBuilder {
        private String userId;
        private String userName;
        private String userAge;

        DemoUserBuilder() {
        }

        public DemoUser.DemoUserBuilder userId(String userId) {
            this.userId = userId;
            return this;
        }

        public DemoUser.DemoUserBuilder userName(String userName) {
            this.userName = userName;
            return this;
        }

        public DemoUser.DemoUserBuilder userAge(String userAge) {
            this.userAge = userAge;
            return this;
        }

        public DemoUser build(a) {
            return new DemoUser(this.userId, this.userName, this.userAge);
        }

        public String toString(a) {
            return "DemoUser.DemoUserBuilder(userId=" + this.userId + ", userName=" + this.userName + ", userAge=" + this.userAge + ")"; }}}Copy the code

The principle of Lombok

If Lombok is not installed for IDEA, our project using Lombok will not compile. After installing it, IDEA will remind us of the methods and properties Lombok generated for us.

With the @data annotation, you can look at the class structure to find getters, setters, toString, and so on.

Since Java 6, Javac has supported the JSR 269 Pluggable Annotation Processing API specification, which allows applications to invoke defined annotations at Java source compilation as long as they implement the API. For example, there is A program A that implements the “JSR 269 API”. The process of compiling source code using Javac is as follows:

  1. Javac analyzes the source code and generates an abstract syntax tree (AST). The plug-in

  2. Call A program that implements “JSR 269 API” in the process of running;

  3. At this point, A program can complete its own logic, including modifying the abstract syntax tree (AST) obtained in the first step;

  4. Javac uses a modified abstract syntax tree (AST) to generate bytecode files;

    The detailed flow chart is as follows:

    As you can see from Lombok’s execution flowchart above, after Javac is parsed into an AST abstract syntax tree, Lombok dynamically modifies the AST to add new nodes (the code Lombok generates for custom annotations) based on its own annotation processor. Finally, the JVM executable bytecode Class file is generated after analysis. Custom annotations using Annotation Processing are modified at compile time as opposed to the JDK’s reflection technology, which is modified dynamically at run time. Reflection is a bit more flexible but incurs a higher performance penalty.

The disadvantage of Lombok

  • In development tools, methods omitted using Lombok annotations will report an error that the definition cannot be found when called. In this case, special treatment is required.
  • Using Lombok eliminates the need for manual setupsetterandgetterMethods such as trouble, but greatly reduced the readability and integrity of the source code, the warmth of the reading of the source code.