Lombok makes Java cool again

Lombok makes Java cool again

Setting up Lombok

Lombok is a compiler plugin, as it converts the annotations in your source code into Java statements before the compiler processes them — the Lombok dependency does not need to present at runtime, so adding Lombok will not increase the size of build artifacts. So you’ll need to download Lombok and add it to your build tool. To?set up Lombok ?with Gradle (it works with?Maven ?too), add this block to the build.Gradle file:

No alt text provided for this image

Since Lombok is a compiler plugin, the source code we write for it is actually?not?valid Java. So you’ll also need to install a plugin for the IDE you are using. Fortunately, Lombok supports all the major Java IDEs. Without the plugin, the IDE has no idea how to parse the code. The IDE integration is seamless. Features such as “show usages” and “go-to implementation” continue to work as expected, taking you to the relevant field/class.

Lombok in action

The best way to learn about Lombok is to see it in action. Let’s dig into some examples on how to apply Lombok to common aspects of a Java application.

Spice Up A POJO

We use plain old Java objects (POJOs) to separate data from processing, making our code easier to read and simplifying network payloads. A simple POJO has some private fields and corresponding getters and setters. They get the job done but only after writing a lot of boilerplate code.

Lombok helps make POJOs more useful, flexible, and structured without writing much additional code. With Lombok, we can simplify the most basic POJO with the?@Data?annotation:

No alt text provided for this image

The?@Data?annotation is really just a convenience annotation that applies multiple Lombok annotations.

  • @ToString ?generates an implementation for the?toString()?method which consists of a “pretty print” version of the object containing the class name and each field and its value.
  • @EqualsAndHashCode ?generates implementations of the?equals?and?hashCode?methods that, by default, uses all non-static, non-transient fields, but are configurable.
  • @Getter?/?@Setter ?generate getter and setter methods for private fields.
  • @RequiredArgsConstructor ?generates a constructor with the required arguments, where the required arguments are final fields and fields annotated with?@NonNull?(more on that later).

That one annotation covers many common use cases simply and elegantly. But a POJO isn’t always enough. A?@Data?class is entirely mutable, which when abused, can increase complexity in an application and limit concurrency usage, both of which hurt the longevity of an application.

Lombok has just the fix. Let’s revisit our?User?class, make it immutable, and add a few other useful Lombok annotations.

No alt text provided for this image

All it takes is the?@Value?annotation.?@Value?is similar to?@Data?except, all fields are made private and final by default, and setters are not generated. These qualities make?@Value?objects effectively immutable. As the fields are all final, there is no argument constructor. Instead, Lombok uses?@AllArgsConstructor?to generate an all-arguments constructor. This results in a fully-functioning, effectively-immutable object.

But being immutable isn’t very useful if you can only create an object using an all args constructor.?As?Effective Java?by Joshua Bloch?explains, builders should be used when faced with many constructor parameters. That is where Lombok’s?@Builder?steps in, automatically generating a builder inner class:

No alt text provided for this image

Using the Lombok-generated builder makes it easy to create objects with many arguments and to add new fields in the future. The static builder method returns a builder instance to set all the properties of the object. Once set, invoke?build()?on the builder to return an instance.

The?@NonNull?annotation can be used to assert that those fields are not null when the object is instantiated, throwing a?NullPointerException?when null. Notice how the avatar field is annotated with?@NonNull?but it is not set. That is because [email protected]?annotation indicates to use “default.png” by default.

Also notice how the builder is using?favoriteFood, the singular name of the property on our object. When the?@Singular?annotation is placed on a collection property, Lombok creates special builder methods to individually add items to that collection, rather than adding the entire collection at once. This is particularly nice for tests as creating small collections in Java is not concise.

Finally, the?toBuilder = true?setting adds an instance method?toBuilder()?that creates a builder object populated with all the values of that instance. This enables an easy way to create a new instance prepopulated with all the values from the original instance and change just the fields needed. This is particularly useful for?@Value?classes because the fields are immutable.

A few annotations let you further configure specialized setter functions.?@Wither?creates “withX” methods for each property that accept a value and returns a cloned of the instance with the one field value updated.?@Accessors?lets you configure automatically created setters. By default, it allows setters to be chained, where like a builder, this is returned rather than void. It also has a parameter,?fluent=true, which drops the “get” and “set” prefix convention on getters and setters. This can be a useful replacement for?@Builder?if the use case requires more customization.

If the Lombok implementation does not fit your use case (and you have looked at the annotation’s modifiers), then you can always just write your own implementation by hand. For example, if you had a?@Data?class but a single getter needed custom logic, simply implement that getter. Lombok will see that implementation is already supplied and will?not?overwrite it with the autogenerated implementation.

With just a few simple annotations, the initial User POJO has gained so many rich features that make it easier to use without putting much burden on us engineers or increasing the time or cost to develop.

Remove component boilerplate code

Lombok isn’t just useful in POJOs — it can be applied at any layer of an application. The following usages of Lombok are particularly useful in the component classes of an app, such as controllers, services, and DAOs (data access objects).

Logging is a baseline requirement for every piece of software, serving as a critical investigation tool. Any class that is doing meaningful work should be logging information. As logging is a cross-cutting concern, declaring a private static final logger in every class becomes instant boilerplate. Lombok simplifies this boilerplate into one annotation that automatically defines and instantiates a logger with the right class name. There are a handful of different annotations depending on the logging framework you are using.

No alt text provided for this image

With a logger declared, next, let’s add our dependencies:

No alt text provided for this image


The?@FieldDefaults?annotation adds the final and private modifiers to all of the fields. The?@RequiredArgsConstructor?creates a constructor that accepts and sets a?UserDao?instance. The?@NonNull?annotation adds a check in the constructor and throws a?NullPointerException?if the?UserDao?instance is null.

But wait, there’s more!

There are so many ways to use Lombok. The above two sections focused on specific use cases, but Lombok can make development easier in many areas. Here are a couple of small examples that show off how to better leverage Lombok effectively.

Although Java 9 introduces the?var?keyword, a?var?can still be reassigned. Lombok provides a?val?keyword which picks up where?var?leaves off, providing local final type inferred variables.

No alt text provided for this image


Some classes just have pure static functions and are never meant to be initialized. Declaring a private constructor that throws an exception is one way prevent it from getting instantiated. Lombok has codified that pattern in its?@UtilityClass?annotation which creates a private constructor that throws an exception, makes the class final, and makes all methods static.

No alt text provided for this image

A common critique of Java is the verbosity created by throwing checked exceptions. Lombok has an annotation to remove the need for those pesky throws keywords:?@SneakyThrows. As you might expect, the implementation is quite sneaky. It does not swallow or even wrap exceptions into a?RuntimeException. Instead, it relies on the fact that at runtime, the JVM does not check for the consistency of checked exceptions. Only javac does this. So Lombok uses bytecode transformations to opt out of this check at compile time. As a result, this results in runable code.


No alt text provided for this image

Side by side comparison

Nothing beats seeing how much code Lombok saves than doing a side by side comparison. The IDE plugin offers a “de-lombok” function that converts most Lombok annotations into the approximate native Java code (the?@NonNull?annotation not converted). Any IDE with the Lombok plugin installed lets you convert most annotations into native Java code (and back again). Let’s return to our?User?class from above.

No alt text provided for this image


The Lombok class is just 13 simple, readable, descriptive lines of code. But after running de-lombok, the class is transformed into over a hundred lines boilerplate that no one wants to see, but everyone wants!

No alt text provided for this image
No alt text provided for this image
No alt text provided for this image


We can do the same for the?UserService?class from above.

No alt text provided for this image

Will result in approximately this Java code.

No alt text provided for this image

Measuring the impact

Grubhub has over a hundred services running to accomplish the needs of the business. We took one of these services and ran the “de-lombok” functionality of the Lombok IntelliJ plugin to see how many lines of code were saved by using Lombok. The result was a change to approximately 180 files, resulting in about 18,000 additional lines of code and 800 deletions of Lombok usages. That is 18,000 lines of auto-generated, standardized, and battle-tested lines of code! On average, each line of Lombok code is saving 23 lines of Java code. With an impact like that, it is hard to imagine using Java without Lombok.

Summary

Lombok has been an excellent way to excite engineers with the appearance of new language features without requiring much effort across the organization. It is certainly easier to apply a plugin to a project than to train all engineers on a new language and port over existing code. Lombok may not have everything, but it certainly provides enough out of the box to have a noticeable impact on the engineering experience.

One other benefit of Lombok is that it keeps our codebases consistent. With over a hundred different services and distributed teams across the world, keeping our codebases in alignment makes it easier to scale teams and reduce the burden of context switching when starting a new project. Lombok is relevant for any version of Java since 6, so we can count on it being available in all projects.

Lombok means much more to Grubhub than just shiny new features. After all, anything Lombok does?could?be just written by hand. As shown, Lombok streamlines the boring parts of the codebase without affecting business logic. This keeps the focus on efforts that provide the most value to Grubhub and are the most interesting to our engineers. It is a waste of time for the writer, reviewer, and maintainer to have such a large portion of the codebase be monotonous boilerplate code. Also, as this code is no longer manually written, it eliminates entire classes of typo errors. The benefits of autogeneration combined with the power of?@NonNull?reduce the chance of bugs and keep our engineering efforts focused on delivering food to you!

Credit: Grubhub Bytes






要查看或添加评论,请登录

Omar Ismail的更多文章

  • OAuth Grant Types (Authorization Code Grant)

    OAuth Grant Types (Authorization Code Grant)

    The authorization code grant type is used to obtain both access tokens and refresh tokens. The grant type uses the…

  • What is Apache Kafka?

    What is Apache Kafka?

    Reference : https://www.qlik.

    2 条评论
  • Multi-Tenant Architecture in a Nutshell

    Multi-Tenant Architecture in a Nutshell

    Thanks to the original writer and article :…

  • Microservices Communication!

    Microservices Communication!

    Thanks To: https://medium.com/design-microservices-architecture-with-patterns/microservices-communications-f319f8d76b71…

    2 条评论
  • What Are the New Features of SpringBoot3 ?

    What Are the New Features of SpringBoot3 ?

    Thanks to : https://medium.com/javarevisited/what-are-the-new-features-of-springboot3-6ddba9af664 1.

    1 条评论
  • OAuth 2.0!

    OAuth 2.0!

    Thanks to the original writer : https://medium.com/@isharaaruna OAuth2.

    2 条评论
  • How to Draw a Technical Architecture Diagram

    How to Draw a Technical Architecture Diagram

    Thanks to the original writer and article : https://levelup.gitconnected.

    2 条评论
  • Event Sourcing Versus Event-Driven Architecture

    Event Sourcing Versus Event-Driven Architecture

    Thanks to the original writer and article :…

  • Best Practices For Your API Versioning Strategy

    Best Practices For Your API Versioning Strategy

    API versioning is critical. But do you know all of the API versioning best practices? Is your API versioning strategy…

    1 条评论
  • Enterprise Architecture Tools

    Enterprise Architecture Tools

    Thanks to the original writer and article : https://medium.com/geekculture/enterprise-architecture-tools-b8165c8c9d7…

社区洞察

其他会员也浏览了