Lombok @Builder generates a builder for our class, and Gson serializes and deserializes such a class without extra configuration, whereas Jackson serializes it directly but needs @Jacksonized or @JsonDeserialize to deserialize it. Serialization converts a Java object to JSON, and deserialization converts the JSON back to a Java object. We need both conversions when a REST API sends or receives a class that Lombok builds.
The following example uses the Article class, which has the fields id, title and tags. We created this class in the Lombok @Builder tutorial.
@Builder
@Getter
@ToString
public class Article {
private Long id;
private String title;
private List<String> tags;
}
1. Serializing @Builder Class
Gson and Jackson both serialize a class annotated with @Builder without extra configuration.
1.1. Gson
The Gson method toJson() serializes the Article object to JSON..
Article article = Article.builder(1L)
.title("Test Article")
.tag("Test Tag")
.build();
//With Gson
Gson gson = new Gson();
String gsonJson = gson.toJson(article);
//Prints {"id":1,"title":"Test Article","tags":["Test Tag"]}
System.out.println(gsonJson);
1.2. Jackson
The Jackson method writeValueAsString() serializes the Article object to JSON.
Article article = Article.builder(1L)
.title("Test Article")
.tag("Test Tag")
.build();
//With Jackson
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(article);
//Prints {"id":1,"title":"Test Article","tags":["Test Tag"]}
System.out.println(json);
2. Deserializing @Builder Class
2.1. Gson
Gson reads the JSON back into an Article object with the method fromJson() and needs no extra configuration for deserialization.
String json = "{\"id\":1,\"title\":\"Test Title\",\"tags\":[\"Test Tag\"]}";
Gson gson = new Gson();
Article gsonArticle = gson.fromJson(json, Article.class);
//Prints Article(id=1, title=Test Title, tags=[Test Tag])
System.out.println(gsonArticle);
2.2. Jackson
By default, Jackson throws the runtime exception InvalidDefinitionException when we deserialize the Article class. Jackson cannot construct the object because the class has no default no-args constructor.
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":1,\"title\":\"Test Title\",\"tags\":[\"Test Tag\"]}";
Article article = mapper.readValue(json, Article.class);
System.out.println(article);
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `com.howtodoinjava.demo.lombok.Article`
(no Creators, like default constructor, exist): cannot deserialize from Object value
(no delegate- or property-based Creator)
at [Source: (String)"{"id":1,"title":"Test Title","tags":["Test Tag"]}"; line: 1, column: 2]
2.2.1. Lombok @Jacksonized
The Lombok annotation @Jacksonized is the simplest solution for deserializing with Jackson. We annotate the @Builder class with @Jacksonized, and Jackson converts the JSON string to a Java object.
@Builder(toBuilder = true)
@Getter
@ToString
@Jacksonized
public class Article {
...
}
String json = "{\"id\":1,\"title\":\"Test Title\",\"tags\":[\"Test Tag\"]}";
ObjectMapper mapper = new ObjectMapper();
Article article = mapper.readValue(json, Article.class);
//prints Article(id=1, title=Test Title, tags=[Test Tag])
System.out.println(article);
2.2.2. Jackson @JsonDeserialize and @JsonPOJOBuilder
The annotation @Jacksonized is an experimental feature, so Lombok may remove it in a future version. Another way to make @Builder work with Jackson is to add Jackson annotations that tell Jackson how to create an instance of the Article class.
Two Jackson annotations support this.
- @JsonDeserialize specifies a custom deserializer that unmarshals the JSON.
- @JsonPOJOBuilder configures the details of a builder class.
@Builder
@Getter
@ToString
@JsonDeserialize(builder = Article.ArticleBuilder.class)
public class Article {
private Long id;
private String title;
private List<String> tags;
@JsonPOJOBuilder(withPrefix="")
public static class ArticleBuilder {
}
}
String json = "{\"id\":1,\"title\":\"Test Title\",\"tags\":[\"Test Tag\"]}";
ObjectMapper mapper = new ObjectMapper();
Article article = mapper.readValue(json, Article.class);
//Prints Article(id=1, title=Test Title, tags=[Test Tag])
System.out.println(article);
3. Conclusion
Gson serializes and deserializes classes annotated with Lombok @Builder without extra configuration, so it is the simplest choice.
If we must use Jackson, @Jacksonized needs the least code. If Lombok removes @Jacksonized in a future version, we can use the Jackson annotations @JsonDeserialize and @JsonPOJOBuilder instead.
Happy Learning !!