3

This is my class:

@Builder
@Value
public class A {
    int id;
    String name;
    @NonNull String lastName;
}

The Lombok @Builder will add the all args constructor.

I need to deserialise a string into a POJO object.

I created the following Jackson mixin containing all three properties:

public abstract class AMixin {
    public AMixin(@JsonProperty("name") String name,
                  @JsonProperty("id") int id,
                  @JsonProperty("lastName") String lastName) {
    }

    @JsonProperty("name")
    abstract String getName();

    @JsonProperty("id")
    abstract int getId();

    @JsonProperty("lastName")
    abstract String getLastName();

}

I deserialise like this:

public static void main(String[] args) throws Exception {


        ObjectMapper mapper = new ObjectMapper();
        mapper.addMixIn(A.class, AMixin.class);

        String ss = "{\"id\":1,\"name\":\"some name\",\"lastName\":\"some name\"}\n";
        A c = mapper.readValue(ss, A.class);
    }

but I get this error:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.bla.test.A` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"id":1,"name":"some name","lastName":"some name"}
"; line: 1, column: 2]
M. Justin
  • 14,487
  • 7
  • 91
  • 130
Marco Dinatsoli
  • 10,322
  • 37
  • 139
  • 253
  • Did you try adding @NoArgsConstructor ? If it does not work check this one https://stackoverflow.com/questions/51464720/lombok-1-18-0-and-jackson-2-9-6-not-working-together – Traycho Ivanov Aug 07 '20 at 21:29
  • @TraychoIvanov I don't want the no args constructor. My class is final and all its fields are final and must be declared in the initiation phase (constructor) – Marco Dinatsoli Aug 07 '20 at 21:49
  • In this case you need this approach with `@JsonDeserialize` , here there is a good example https://stackoverflow.com/a/48801237/9671280 – Traycho Ivanov Aug 07 '20 at 21:55
  • @TraychoIvanov the whole idea of mixin is to avoid adding Jackson annotation in your POJO so I'd prefer to know why my mix is not working. – Marco Dinatsoli Aug 07 '20 at 22:07
  • @Marcoo this is pure lombok issue, believe me or not the once chance to solve it by testing the latest jackson versions otherwise you need to accept the compromise. – Traycho Ivanov Aug 07 '20 at 22:19
  • @TraychoIvanov I found the solution :) (no compromise on POJO being clean) – Marco Dinatsoli Aug 07 '20 at 22:27
  • 1
    Does this answer your question? [Lombok 1.18.0 and Jackson 2.9.6 not working together](https://stackoverflow.com/questions/51464720/lombok-1-18-0-and-jackson-2-9-6-not-working-together) – Traycho Ivanov Aug 07 '20 at 22:30

2 Answers2

2

I found the answer.

Add lombok.config file with content:

lombok.anyConstructor.addConstructorProperties=true
Marco Dinatsoli
  • 10,322
  • 37
  • 139
  • 253
2

The issue here is that Jackson expects a no-argument constructor or some other configured way of creating the object. However, because of the @Builder annotation on A, the no-argument constructor is not present, only the Lombok-generated all-argument constructor A(int id, String name, String lastName).

As of Lombok v1.18.14, the @Jacksonized annotation can be added to the class with the @Builder annotation, which automatically configures the builder to be used for Jackson deserialization.

@Jacksonized
@Builder
@Value
public class A {
    int id;
    String name;
    @NonNull String lastName;
}

The Lombok documentation for @Jacksonized describes this annotation in more detail:

The @Jacksonized annotation is an add-on annotation for @Builder and @SuperBuilder. It automatically configures the generated builder class to be used by Jackson's deserialization. It only has an effect if present at a context where there is also a @Builder or a @SuperBuilder; a warning is emitted otherwise.

[...]

In particular, the annotation does the following:

  • Configure Jackson to use the builder for deserialization using @JsonDeserialize(builder=_Foobar_._Foobar_Builder[Impl].class)) on the class (where Foobar is the name of the annotated class, and Impl is added for @SuperBuilder). (An error is emitted if such an annotation already exists.)
  • Copy Jackson-related configuration annotations (like @JsonIgnoreProperties) from the class to the builder class. This is necessary so that Jackson recognizes them when using the builder.
  • Insert @JsonPOJOBuilder(withPrefix="") on the generated builder class to override Jackson's default prefix "with". If you configured a different prefix in lombok using setterPrefix, this value is used. If you changed the name of the build() method using using buildMethodName, this is also made known to Jackson.
  • For @SuperBuilder, make the builder implementation class package-private.

Note: This issue has nothing to do with the usage of a mixin, which can be verified by moving Jackson configuration from the mixin to the class itself and observing that the issue is still present.

M. Justin
  • 14,487
  • 7
  • 91
  • 130