Tuesday, March 19, 2019

JSONSerialize and JSONDeserialize with Lombok custom deserialization builders

I was in a situation where I was using both Lombok and Jackson to manage some Java objects being serialized and deserialized.

My objects were declared in this format:
@Builder(toBuilder = true)
@JsonDeserialize(MyClass.MyClassBuilder.class)
@Dataclass MyClass {

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd")
    @JsonSerialize(using = LocalDateSerializer.class)
    @JsonDeserialize(using = LocalDateDeserializer.class)
    LocalDate myDate;

    @JsonPOJOBuilder(withPrefix = "")
    public static final class MyClassBuilder {

    }
}
I would run deserialization using a regular JSON ObjectMapper instance against a JSON object of the form:
{ "myDate": "20181207"}

 and get an error that looked something like:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value ('20181207')

Some searching made me hypothesize that this was due to the fact that I'm doing my deserialization using a builder, and that the annotations were being ignored.  I changed the code as follows and it began to deserialize properly:

@Builder(toBuilder = true)
@JsonDeserialize(MyClass.MyClassBuilder.class)
@Dataclass MyClass {
    
    LocalDate myDate;

    @JsonPOJOBuilder(withPrefix = "")
    public static final class MyClassBuilder {
        
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd")
        @JsonSerialize(using = LocalDateSerializer.class)
        @JsonDeserialize(using = LocalDateDeserializer.class)
        LocalDate myDate;
    }
}