Lombok Builder with Jackson

Lombok comes with a very convenient way of creating immutable objects with the builder pattern. However, if you need to serialize or deserialize JSON objects then there isn’t any support straight of the box for it. In this post, we will look at how we can use Lombok Builder with Jackson when working with JSON.

I am a huge fan of Lombok, it is definitely one of my favorite libraries for Java programming. It removes so much unnecessary boilerplate code and makes Java programming way more fun. Traditionally Lombok is used with getters and setters but it can generate immutable classes with the builder pattern.

The builder pattern has many benefits. It allows you to create immutable objects that are thread-safe. But perhaps most importantly; if you have a class with many required fields then you would normally require a constructor that takes many arguments and this looks extremely ugly. If you use the builder pattern then this won’t be needed anymore.

I previously wrote a blog on Immutability with Lombok builder pattern and if you haven’t read it, then I recommend checking that one out before proceeding.

Why doesn’t it work straight out of the box?

So why exactly doesn’t Lombok Builder with Jackson work well together with each other? As of writing (Lombok 1.18.4 and Jackson 2.9.7); Lombok by default creates builder methods that look like the following.

Person person1 = Person.builder()
    .name("Viktor")
    .age(25)
    .build();

However, Jackson expects the builder methods that looks like this.

Person person2 = Person.builder()
    .withName("Viktor")
    .withAge(25)
    .build();

So when Jackson tries to deserialize an object, it will not find any matching methods to use.

Making Lombok Builder with Jackson work

Luckily though, there is a solution to this problem, but it requires writing some boilerplate code, which goes against the main purpose of Lombok.

What you can do is to create the builder class yourself so that you can add Jackson annotations to it. Lombok will then re-use this class and add all the builder methods to it. The code example below is a fully functional Lombok Builder with Jackson.

@Data
@JsonDeserialize(builder = Person.PersonBuilder.class)
@Builder(builderClassName = "PersonBuilder", toBuilder = true)
public class Person {

  private final String name;
  private final int age;

  @JsonPOJOBuilder(withPrefix = "")
  public static class PersonBuilder {

  }

}

As you can see, it requires a few more lines of code, but it is still a lot better than writing the full builder pattern by yourself.

Making @JsonIgnore (and other annotations) work

Lombok won’t by default add annotations to the generated builder methods, in order to do so, you must utilize the lombok.config file.

Create a lombok.config file in the base package of your project, this config can also be overridden on package level by overriding the file there.

# True if it the config file is located in the root package of your project
config.stopBubbling = true
 
lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonIgnore
lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty

You can keep on appending more annotations that should be copied to the builder method. This also works for the traditional getter/setters as well.

Summary

We have now looked at how you can benefit from the awesome Lombok library for the Builder Pattern when working with the most popular JSON library, Jackson, in Java.

The main issue was that it wasn’t possible to tell Jackson to not use the “with” prefix on the builder method without manually creating the builder class yourself. This issue might be solved with an upcoming Lombok feature called: onX. Where you can add annotations to fields, methods and classes. I haven’t tried this, and it is a very early experimental feature. So for now, it is better to go with the solution that we looked at.

4 thoughts on “Lombok Builder with Jackson”

  1. There might be a small typo in the “Why doesn’t it work straight out of the box?” section. You say:
    > Jackson by default expects builder methods that looks like the following.

    and then again

    > However, Jackson expects the builder methods that looks like this.

    Maybe the first one should be something like: “Lombok by default creates builder methods that look like the following”?

    Anyway, thanks for the article, it was helpful.

  2. Hi,

    Thanks for the well written post. I am trying to make Jackson work with @SuperBuilder instead of @Builder. Do you have any tips for that?

Leave a Reply