Immutable classes with Spring Boot, Lombok and Jackson
I like to create immutable classes. When using Lombok we can easily create immutable classes.
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;
@Value
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE) //Hides the constructor to force useage of the Builder.
public final class Person {
private final String firstName;
private final String lastName;
}
This class Person with the @Value
annotation will create an immutable class with an all args constructor.
The @Builder
will add a Builder pattern to the Person class, so I can use it like this:
Person person = Person.builder()
.firstName("Elvis")
.lastName("Presley")
.build();
To use this class in Jackson we need to make some slight changes in the way we build our ObjectMapper and compile our Java classes.
By default Jackson will use a no args constructor and setters to create the desired instance.
We can use a @JsonCreator
and @JsonProperty
to indicate what constructor Jackson needs to use and how to map properties.
Since we use Lombok to generate a constructor we cannot easily add these annotations to the constructor. We can add some Jackson specific modules to look at the parameter names of the constructor. Together with adding a parameter property as compiler argument to javac command in our gradle, the correct constructor will be used by Jackson. The compiler arguments will instruct the compiler to keep the argument names. In this case we need to keep the argument names in the constructor so Jackson knows which parameters it takes. By default the java compiler drops the parameter names and replaces those by arg1, arg2, etc.
dependencies {
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jdk8"
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
implementation "com.fasterxml.jackson.module:jackson-module-jackson-module-parameter-names"
}
We add some instructions for Lombok in the lombok.config
in the root of our project. It will be automatically be picked up.
lombok.addLombokGeneratedAnnotation = true
lombok.anyConstructor.addConstructorProperties = true
Now we can configure our ObjectMapper bean to automatically register the modules found on the classpath.
@Bean
ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules(); //Registers all modules on classpath
return mapper;
}
Now Jackson will be using the correct constructor for our immutable class.
-
More info on Lombok: projectlombok
-
More info on Jackson Java8 modules: jackson-modules-java8