These 3 Lombok Annotations Might Skyrocket In Popularity After Java 17 Migration
Let’s discuss Lombok’s @With, @Builder, and @NonNull annotations and see how we can use them with Java 17 records.

@With
Even though records are immutable objects, sometimes we might need to change the attributes of an object.
To solve this, we can create a new instance of the object and copy all the old values, except for the one that needs to be changed. Our method will return a new instance with the modified field and the old instance will not be affected:

If we add a similar “with” method for one or two other fields, we can already imagine the boilerplate code piling up.
Fortunately enough, we can use Lombok’s @With to generate the these methods:

@Builder
Instantiating bigger record objects with nullable fields might be troublesome: Passing “null” is a known code smell regardless if it is done to call a method or to instantiate an object.
We avoid cluttering the code with the use of the builder design pattern:
public record User(
String firstName,
String lastName,
Long id,
String email,
String username) {
public static User.Builder builder() {
return new Builder();
}
static class Builder {
String firstName;
String lastName;
Long id;
String email;
String username;
public Builder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder id(Long id) {
this.id = id;
return this;
}
// same for the other fields
public User build() {
return new User(
this.firstName,
this.lastName,
this.id,
this.email,
this.username);
}
}
}Now, we can instantiate the record like this:
User user = User.builder()
.firstName("john")
.id(12374L)
.build();You may already know Lombok’s @Builder annotation: it’s working for records too!

Basically, we can annotate a record class with @Builder and Lombok will generate all the code from the snippet above, for us:

@NonNull
When using records, we can make sure a field is not null by manually checking it inside the constructor:
public record User(
String firstName,
String lastName,
Long id,
String email,
String username) {
User(String firstName, String lastName, Long id, String email, String username) {
if (firstName == null) {
throw new IllegalArgumentException("'firstName' cannot be null!");
}
this.firstName = firstName;
this.lastName = lastName;
this.id = id;
this.email = email;
this.username = username;
}
}Because the validation is made in the constructor and the object is immutable, we can be sure the object will always be in a valid state — even if we create it using a builder or if we add with-ers.

Lombok’s @NonNull comes in handy for this. We can annotate the mandatory fields with this annotation and Lombok will do its magic:

Conclusion
In this article, we discussed the Lombok annotations that play nicely with immutable objects and with the new record type.
We learned that we can use @With to create new instances of the record, with modified fields.
After that, we saw that the already familiar @Builder annotation makes perfect sense for the record objects as well.
Finally, we discussed Lombok’s @NonNull which can help us guard against invalid data being passed into the constructor.
Thank You!
Thanks for reading the article and please let me know what you think! Any feedback is welcome.
If you want to read more about clean code, design, unit testing, functional programming, and many others, make sure to check out my other articles.
If you like my content, consider following or subscribing to the email list.
Finally, if you consider becoming a Medium member and supporting my blog, here’s my referral.
Happy Coding!
