Learn to serialize and deserialize Lombok @Builder annotated class with Jackson library.
For demo purpose, we are using Article
class have few field members. We have created this class during the Lombok @Builder tutorial.
@Builder
@Getter
@ToString
public class Article {
private Long id;
private String title;
private List<String> tags;
}
1. Serializing @Builder Class
The serialization process is very simple and we do not do anything extra. It works out of the box.
1.1. Gson
Java program to serialize @Builder class using Gson.
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
Java program to serialize @Builder class using Jackson.
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 works great for deserialization as well, without any extra configuration. We can use it directly.
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, if we try to deserialize the Article class we will get the runtime exception InvalidDefinitionException. The Jackson is not able to find a way to construct the object in the absence of a 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
Using @Jacksonized annotation is the simplest solution if you are using Jackson for deserialization purposes. Just annotate the @Builder class with @Jacksonized annotation and we are good for converting the JSON string to 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
Keep in mind that @Jacksonized
is an experimental feature and may be removed in future versions. Another approach to make @Builder work with Jackson is by adding Jackson annotation which can help Jackson to figure out how to create an instance of Article class.
The two such annotations are:
- @JsonDeserialize – used to specify custom deserializer to unmarshal the JSON.
- @JsonPOJOBuilder – used to configure 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
Based on the above conversation, Google Gson works best for serialization and deserialization purposes on classes annotated with Lombok @Builder
. It should be the preferred approach as it works out of the box.
If using Jackson is required, we have @Jacksonized
annotation that works best with very little code. In the future, if @Jacksonized is not part of Lombok then during library upgrades we can use other Jackson annotations to make deserialization work.
Happy Learning !!