Lombok is NOT DEADL̶o̶m̶b̶o̶k̶ ̶i̶s̶ ̶d̶e̶a̶d̶

David Kihato
5 min readJan 4, 2023

--

Image generated on midjourney

Introduction

With the introduction of Java 14 in March 2020, the Java language added support for records, which are a concise way to define immutable data classes. With records, the Java compiler generates the equals, hashCode, toString methods as well as the private, final fields and public constructor. Therefore you don’t have to provide the boilerplate code of getters and setters and all-args constructor which most of us used Lombok for. Records rendered Lombok “dead” as some in the community would say.

However, Lombok is still a useful tool even with the addition of records in Java. In this article, I will highlight several uses of Lombok that will show that it is still highly relevant.

1. Logging

Logging is an important feature that helps spot mistakes and debug code. It is analogous to the black-box in an airplane. In order to log prior to Lombok, you’d have to include the following static field

private static Logger LOGGER = LoggerFactory.getLogger(MySuperApplication.class);

to your code. Notice the reference of the owning class MySuperApplication.class. This is important so that the logger may know from where you are logging from. This is quite a mouthful and is prone to mistakes. Copy-pasters would copy the line above and paste it to their classes to avoid typing in each class but it’s prone to mistakes since one might forget to change the class reference. This obviously will print inaccurate information.
With Lombok, all you have to do is include @Slf4j annotation to your class and voila, you have logging functionality.

@Slf4j
public class MySuperApplication {
public static void main(String[] args) {
log.info("This is an info level message");
}
}

Copy-pasters, go ahead and copy-paste the annotation. Logback has your back!

2. Exceptions, exceptions, exceptions 🤦

You have found a super dupa method and you want to use it in your code but your IDE underlines your code with a red-squiggly line telling you that the exceptions thrown by the method must be handled. What if you don’t care about that exception? What if you just want to ignore it and move on with your life, what do you do? You end up doing the following:

public static void main(String[] args) {

try {
superDupaMethod();
} catch (Exception e) {
// I don't care about the exception
}
}

Fine, the try-catch works, but what does it do to your clean formatted code…arrghhh!

Enter Lombok!! By just adding @SneakyThrows annotation, it gets rid of the red-squiggly line and you have your clean formatted code intact. Yeah!!!

@SneakyThrows
public static void main(String[] args) {

superDupaMethod();
}

3. Builder

Suppose you have the following class:

public static class Foo {
private Double a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
}

Assuming some of those fields are allowed to be null. How can we instantiate that class? Constructor? — out of the question. Using a constructor is just too much work. What about using setters? Sure, let’s try.

public static void main(String[] args) {
var foo = new Foo();
foo.setA(1d);
foo.setE(5d);
foo.setF(6d);
foo.setG(7d);
foo.setY(25d);
foo.setZ(26d);
}

That works, right? Well…yes, but do we have to repeat foo., foo..

Why don’t we see what Lombok has in its bag of cool tricks…

Enter @Builder!!

public static void main(String[] args) {
var foo = Foo.builder().a(1d).e(5d).f(6d).g(7d).y(25d).z(26d).build();
}

@Builder
public static class Foo {
@Setter
private Double a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
}

Using the @Builder annotation, Lombok generates a builder pattern for our Foo class and therefore we are able to set our fields using the fluent pattern and construct our class using .build() method. Isn’t that cool, right?!? Lombok generates the boiler plate code for you so that you don’t have to.

4. Dependency Injection

Spring recommends constructor over field dependency injection. For example the following code snippet is frowned upon.

@Component
public class MySuperApplication {
@Autowired
EntityManager entityManager;
@Autowired
AService aService;
@Autowired
BService bService;
@Autowired
CService cService;
@Autowired
DService dService;
@Autowired
EService eService;
@Autowired
FService fService;
@Autowired
ARepository aRepository;
@Autowired
BRepository bRepository;
@Autowired
CRepository cRepository;
@Autowired
DRepository dRepository;
@Autowired
ERepository eRepository;
@Autowired
FRepository fRepository;
}

This is what is recommended:

@Component
public class MySuperApplication {
EntityManager entityManager;
AService aService;
BService bService;
CService cService;
DService dService;
EService eService;
FService fService;
ARepository aRepository;
BRepository bRepository;
CRepository cRepository;
DRepository dRepository;
ERepository eRepository;
FRepository fRepository;

public MySuperApplication(EntityManager entityManager, AService aService, BService bService, CService cService, DService dService, EService eService, FService fService, ARepository aRepository, BRepository bRepository, CRepository cRepository, DRepository dRepository, ERepository eRepository, FRepository fRepository) {
this.entityManager = entityManager;
this.aService = aService;
this.bService = bService;
this.cService = cService;
this.dService = dService;
this.eService = eService;
this.fService = fService;
this.aRepository = aRepository;
this.bRepository = bRepository;
this.cRepository = cRepository;
this.dRepository = dRepository;
this.eRepository = eRepository;
this.fRepository = fRepository;
}
}

This is too verbose in my opinion and secondly, if I need to add another field, I have to add it in the constructor parameters too and also assign it inside the constructor. That’s just to much work, don’t you think?

So this is how Lombok helps me to clean up my code. Using the @RequiredArgsConstructor annotation, I am able to achieve the same functionality while keeping my code clean and neat. This annotation generates a constructor with parameters for each uninitialized field marked as final or annotated with @NotNull.

@RequiredArgsConstructor
@Component
public class MySuperApplication {
final EntityManager entityManager;
final AService aService;
final BService bService;
final CService cService;
final DService dService;
final EService eService;
final FService fService;
final ARepository aRepository;
final BRepository bRepository;
final CRepository cRepository;
final DRepository dRepository;
final ERepository eRepository;
final FRepository fRepository;
}

See how neat my code is. In fact, it’s even better than the first solution where I had to add @Autowired annotations for each field declared.

Conclusion

In conclusion, Lombok is not dead even with the introduction of records in Java. It is still a valuable tool for reducing boilerplate code and providing useful features that go beyond what records offer. I hope this convinces you not to drop the Lombok library just yet from your project.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

David Kihato
David Kihato

Written by David Kihato

Self taught Software Engineer for over 10 years

No responses yet

Write a response