How to use Jackson to deserialize external Lombok builder class

Solution 1:

You can customize your ObjectMapper as follows:

    ObjectMapper mapper = new ObjectMapper();
    mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
        @Override
        public Class<?> findPOJOBuilder(AnnotatedClass ac) {
            if (ExternalClass.class.equals(ac.getRawType())) {
                return ExternalClass.ExternalClassBuilder.class;
            }
            return super.findPOJOBuilder(ac);
        }

        @Override
        public Value findPOJOBuilderConfig(AnnotatedClass ac) {
            if (ac.hasAnnotation(JsonPOJOBuilder.class)) {
                return super.findPOJOBuilderConfig(ac);
            }
            return new JsonPOJOBuilder.Value("build", "");
        }
    });

This will

  • explicitly configure that deserialization for ExternalClass uses its builder, and
  • set the default prefix for builder setter methods to "" (except when the @JsonPOJOBuilder annotation is present).

If you do not want to list all external classes explicitly in findPOJOBuilder(), you can of course programmatically look into the class to check whether it has a inner class that looks like a builder.

Solution 2:

This can be accomplished by creating two mixins: one for ExternalClass (specifying the builder to use) and one for ExternalClass.ExternalClassBuilder (specifying the lack of a prefix in the builder methods).

@JsonDeserialize(builder = ExternalClass.ExternalClassBuilder.class)
public interface ExternalClassMixin {
}

@JsonPOJOBuilder(withPrefix="")
public interface ExternalClassBuilderMixin {
}

This serializes and deserializes the JSON in the desired manner:

String json = "{\"name\": \"The Name\", \"data\": \"The Data\"}";

ObjectMapper mapper = new ObjectMapper()
        .addMixIn(ExternalClass.class, ExternalClassMixin.class)
        .addMixIn(ExternalClass.ExternalClassBuilder.class, ExternalClassBuilderMixin.class);

System.out.println(mapper.readValue(json, ExternalClass.class));
System.out.println(mapper.writeValueAsString(mapper.readValue(json, ExternalClass.class)));

Output:

ExternalClass(name=The Name, data=The Data)
{"name":"The Name","data":"The Data"}