It is well known that Java server code is riddled with POJOs (Plain old Java object).
POJOs are classes whose soul purpose is to store information and provide access to it.
For example, the following class is a simple one, comprising merely two class members and 33 lines of code. Nevertheless, it is still 30 lines longer than it can be, creating a significant overhead.
public class Person {
private Long id;
private String name;
public Person(Long id, String name) {
this.id = id;
this.name = name;
}
@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(id, employee.id) && Objects.equals(name, employee.name) && Objects.equals(company, employee.company) && Objects.equals(email, employee.email);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Naturally, for "richer" classes the amount of code boilerplate grows dramatically.
Furthermore, this code needs to be maintained, as class members can change,
which in turn might introduce bugs.
What if we could reduce to this:
@Data
public class Person {
private Long id;
private String name;
}
Such a clean and crisp looking class, devoid of the clutter of redundant getters, setters, default constructors etc*, eliminates the need for updates and adjustments when changing a member.
* The full code is generated during project compilation by a neat Java library called "Project Lombok".
Project Lombok
Although Project Lombok (released under MIT license) is not new, it still suffers a relative anonymity and is sometimes unknown to even experienced Java developers.
It provides an option to drastically reduce a Java project boilerplate and replace it with cool annotations, such as the "@Data" above.
A brief review the project's most useful features
* For further information take a look at the complete list of Lombok features.
Builder design pattern allows one to create clear and concise code for complex objects initialisation, that would otherwise require a tedious effort.
@Builder
public class Person {
private final Long id;
private final String name;
}
------------------------------
// And use it like this
Person person = Person.builder().id(123L).name("John Doe").build();
A one liner that can save you a huge amount of getters and setters bundled inside your class, and also automatic default, required or all arguments constructors.
*generates a constructor with a parameter for each final but immediately initialised or uninitialised @NonNull fields
Now you can modify your class members without dealing with annoying errors of messed up constructor arguments and missing getters/setters.
A getter function annotated with @Getter(lazy=true) will run only for the first invocation.
On consequent invocations a memoized value will be returned.
This is useful in cases where the getter function is "expensive" in terms of complexity.
This class level annotation will cause Lombok to generate both equals and hashCode methods, as the two are tied together intrinsically by the hashCode contract.
This class level annotation generates an implementation of the toString method.
* It's worth noting that the above methods (toString, hashCode and equals) are especially prone to errors and bugs when implemented manually, due to the fact that they need to be updated every time a class structure is modified.
A shortcut to have the @ToString, @EqualsAndHashCode, @Getter, @Setter (on non final fields) and @RequiredArgsConstructor* with one annotation.
*Constructor wont be generated if an explicit constructor is already present.
@Data annotation also has an option to create a static factory method for generating our class.
@Data(staticConstructor="make")
public class Person {
private Long id;
private String name;
}
Will make the generated constructor private and will create a public factory method named "make" that will return an instance of class "Person"/
Person me = Person.make();
This annotation indicates that the member will be checked for "null" and in case null is assigned a NullPointerException will be thrown.
This null check will be done on the relevant setter and on relevant constructor.
public class Person {
private @NonNull Long id;
private String name;
}
The @Cleanup annotation can be used to ensure that allocated resources are released, the resource marked with this annotation is wrapped in try-finally block, and a function close() will be called when "finally" is reached.
If the "cleanup" function is not named "close", you can provide an alternative name via annotation "value" attribute
@Cleanup InputStream inputStream = new FileInputStream(args[0]);
A very useful annotation that eliminates the need to copy-paste a declaration of a static logger in every class.
Annotating your class with @Log will provide you with "ready to go" static log object.
@Log
public class Person {
private final @NonNull Long id;
private final String name;
public void doSomething() {
//my code here
log.debug("this was logged!");
}
}
Installation
Or download its JAR here and add it manually.
Support by IDEs
Lombok is supported by multiple IDEs such as Intellij IDEA, Eclipse, VS Code, NetBeans and others, meaning that you will be able to see the dynamically generated methods generated by Lombok as part of your development process.
Summary
Up until now I've not said anything bad regarding usage of Lombok in your Java codebase, in fact we have enjoyed using it ourselves and rare were the cases where Lombok didn't match our expectations.
However there are also some counter arguments that deserve to be noted.
Argument #1: Lombok uses an internal API in order to modify existing code during a compile phase, so it can also be referred to as "hack", meaning that there's a chance that Lombok will stop working after one of the major Java version updates
Although this option exists, so far we had no problems upgrading.
We moved through quite a few major versions of Java without any issues so far.
This project is supported by a large and dedicated community, perhaps that the reason it went so smooth :)
Argument #2: It will run on ECJ and Suns Javac only.
While technically this is true, the vast majority of VMs out there, if they ship a compiler at all, pack one of these two. References
From my perspective Lombok adds a healthy dose of clarity to your code, reducing the amount of annoying bugs and partially compensating for lack of unit tests in your POJOs.
Comments