Use Lombok to Cleanly and Elegantly Optimize Your Entity/JavaBean Code — A Neat Java Trick

Lombok is a third-party Java library. In projects we often define lots of JavaBeans as entity classes, then use IDE shortcuts to generate getter/setter/toString/equals methods — the code looks huge, and worse, renaming requires batch replacement that can go wrong. Lombok can generate that complex yet low-level code at compile time.

I’ve always believed that laziness is a virtue for programmers — only by making humans lazier do we improve efficiency, leaving repetitive and simple work to machines. Today I’m introducing a third-party library that boosts efficiency and lets you be lazy: Lombok. This time I’ll mainly show how to use Lombok to optimize your entity-class code, leaving the repetitive, simple getter/setter/toString/equals code to the program.

Lombok is a third-party Java library. In projects we often define lots of JavaBeans as entity classes, then use IDE shortcuts to generate getter/setter/toString/equals methods — the code looks huge, and worse, when you need to rename something you must do batch replacement, which can go wrong. It’s painful. Lombok can generate that complex yet low-level code at compile time. Official site: https://projectlombok.org/, GitHub: https://github.com/rzwitserloot/lombok

First, add the jar to the project. I use Maven for dependencies, so here’s the Maven pom.xml:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.2</version>
    <scope>provided</scope>
</dependency>

Then install the plugin. To make the IDE not complain about our lazy style, install the Lombok plugin. I use IDEA, so as an example: go to File > Settings > Plugins, search for “Lombok Plugin”, click Install plugin, and restart IDEA.

/31ca9e940cf949d29a3981593d0d2bc4.png

Since I’ve moved to Spring Boot development, I use annotations wherever possible. With Lombok’s help, the entity class becomes:

@Data
public class Link {
    private String href;
    private String text;
    private String target;
}

As you can see, there’s no getter/setter/toString code — just one @Data annotation, which is lombok.Data. This @Data includes @ToString, @Getter, @Setter, @EqualsAndHashCode, @NoArgsConstructor. What does each do? Let’s look at the compiled Link.class:

package com.neilren.neilren4j.entity;

public class Link {
    private String href;
    private String text;
    private String target;

    public Link() {
    }

    public String getHref() {
        return this.href;
    }

    public String getText() {
        return this.text;
    }

    public String getTarget() {
        return this.target;
    }

    public void setHref(String href) {
        this.href = href;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setTarget(String target) {
        this.target = target;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Link)) {
            return false;
        } else {
            Link other = (Link)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                label47: {
                    Object this$href = this.getHref();
                    Object other$href = other.getHref();
                    if (this$href == null) {
                        if (other$href == null) {
                            break label47;
                        }
                    } else if (this$href.equals(other$href)) {
                        break label47;
                    }

                    return false;
                }

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

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

                return true;
            }
        }
    }

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

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $href = this.getHref();
        int result = result * 59 + ($href == null ? 43 : $href.hashCode());
        Object $text = this.getText();
        result = result * 59 + ($text == null ? 43 : $text.hashCode());
        Object $target = this.getTarget();
        result = result * 59 + ($target == null ? 43 : $target.hashCode());
        return result;
    }

    public String toString() {
        return "Link(href=" + this.getHref() + ", text=" + this.getText() + ", target=" + this.getTarget() + ")";
    }
}

Now it’s clear: @Data includes @ToString, @Getter, @Setter, @EqualsAndHashCode, @NoArgsConstructor. @ToString adds a toString() method; @Getter and @Setter add get() and set() methods; @EqualsAndHashCode adds equals(Object o) and hashCode(); @NoArgsConstructor adds a no-arg constructor — here, Link(). Pretty neat, right?

A few more handy annotations:

@NonNull: adding @NonNull to a method or constructor adds a null check; on a null value it throws a NullPointerException.

@Cleanup: when using resources like InputStream/OutputStream, it auto-releases them for us — i.e., adds a close() call.

There are many more annotations I won’t cover; these common ones are basically enough. Next, a logging annotation @Slf4j. Once we bring in Lombok, @Slf4j becomes available: add @Slf4j above the class name, then use log.info() or log.error() inside the class to output and record logs:

@Slf4j
@Service
public class IpInfoService extends BaseService {
    public AlicmapiIP getIpInfo(String ip) {
        try {
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
}

The log output location and level can be configured via config files.

Finally, a note on Lombok: there’s been some debate on whether to use it. Use it according to your actual scenario.