Reduce Java boilerplate (Lombok)

Reduce Java boilerplate (Lombok)

reduce java boilerplate (Lombok)

Overview

Have you ever had a feeling that a significant amount of code you write is redundant? It’s not a secret that Java can be quite verbose and often you just follow a contract of this programming language. Luckily, you’re not the only one who worries about it. As a result, a great solution to deal with it appeared to reduce Java boilerplate – Lombok.

Setup

In order to use Lombok, the following Maven dependency should be added:

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.12</version>
</dependency>

Technically, Lombok acts as an annotation processor that adds code to your classes at compile time. That’s why for development we should enable annotation processing in IDE.

If you’re using IntelliJ IDEA, make sure that “Enable annotation processing” is enabled at:
Preferences | Build, Execution, Deployment | Compiler | Annotation Processors

Getters and setters

In order to access object properties, getters and setters are defined:

public class Employee {
   private String fullName;
   private String position;

   public Employee() {}

   public String getFullName() {
       return fullName;
   }

   public void setFullName(String fullName) {
       this.fullName = fullName;
   }

   public String getPosition() {
       return position;
   }

   public void setPosition(String position) {
       this.position = position;
   }
}

To be honest, since these methods don’t have any custom logic, they are redundant. Especially, when a class has a lot of properties. So, let’s try to reduce the Java boilerplate.

Would you like if it looked in the following way, but still allowed to call getter/setter methods ?

@Getter
@Setter
public class Employee {
   private String fullName;
   private String position;

   public Employee() {}
}

@Getter and @Setter annotations specify that corresponding methods will be created automatically.

Constructors

Constructors can be divided into three types:

  • Without arguments
  • With all arguments
  • With required arguments

If any of these constructors do not have a custom logic except just setting the value of an argument to a corresponding property or if it’s empty at all in case of a default constructor, then they don’t give a programmer any important information except their presence.

Lombok supports 3 annotations for the mentioned constructor types:

  • @NoArgsConstructor
  • @AllArgsConstructor
  • @RequiredArgsConstructor

So, the let’s have a look at an example:

public class Employee {
    private String fullName;
    private String position;

    public Employee() {}

    public Employee(String fullName, String position) {
        this.fullName = fullName;
        this.position = position;
    }
}

Using Lombok it would look like this:

@NoArgsConstructor
@AllArgsConstructor
public class Employee {
    private String fullName;
    private String position;
}

Equals, hashCode and toString

Based on Java best practices, you should always add equals, hashCode and toString methods. Often it’s enough to let these methods to be auto-generated by IDE. Let’s have a look at the class we’ve used before with the mentioned generated methods:

@Getter
@Setter
public class Employee {
   private String fullName;
   private String position;

   public Employee() {}

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(fullName, employee.fullName) &&
                Objects.equals(position, employee.position);
    }

    @Override
    public int hashCode() {
        return Objects.hash(fullName, position);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "fullName='" + fullName + '\'' +
                ", position='" + position + '\'' +
                '}';
    }
}

Thanks to Lombok, these methods can be auto-created via @EqualsAndHashCode and @ToString annotations:

@Getter
@Setter
@EqualsAndHashCode
@ToString
public class Employee {
    private String fullName;
    private String position;

    public Employee() {}
    
}

Get things together

Usually, classes have either all or majority of the mentioned boilerplate: one or more constructors, getter/setter, equals(), hashCode() and toString() methods. Often they don’t have any custom logic and so can be easily configured declaratively via annotations. We’ve already seen how to do it, but Lombok also provides annotations that combine others:

  • @Data – includes @RequiredArgsConstructor, @Getter, @Setter, @EqualsAndHashCode, @ToString
  • @Value – immutable version of @Data. It makes a class and properties final, does not generate setters, but the rest is the same as for @Data

Isn’t it amazing to reduce all the Java boilerplate with just a single annotation ?

Logging

It’s hard to imagine a modern application without a configured logging. In order to start writing logs, a configuration is added and a logger object is defined in the code.

public class EmployeeService {
 private static final Logger log = Logger.getLogger(Employee.class.getName());
}

Lombok provides the following annotations to replace such a line which is repeated in any service:

  • @Log – creates private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
  • @Log4j2 – creates private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
  • @Slf4j – creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

Null checks

Adding a @NonNull for a method parameter, Lombok adds the following null check:

if (paramName == null) {
      throw new NullPointerException("paramName is marked @NonNull but is null");
}

Utility classes

A utility class is a class that is just a namespace for functions. No instances of it can exist, and all its members are static.

Lombok supports @UtilityClass annotation to:

  • automatically generate a private constructor that throws an exception
  • make a class final
  • make methods static

Conclusions

We’ve covered a great solution that makes Java code cleaner and more readable. It allows not to waste time writing and reading a lot of boilerplate code. Using Lombok a developer can concentrate more on business logic rather than following various language-specific contracts.

In this article, only part of the existing Lombok functionality has been covered. It has much more useful annotations. Also, these annotations can have configuration options to adjust the functionality. All the details can be found in the official docs. It worth trying!

Leave a Reply

Your email address will not be published. Required fields are marked *