Lombok 1.18.0 and Jackson 2.9.6 not working together

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP

Lombok 1.18.0 and Jackson 2.9.6 not working together



The deserialization is failing after the update.



I updated my micro-service from Spring 1.5.10.RELEASE to Spring 2.0.3.RELEASE and also updated the lombok from 1.16.14 to 1.18.0 and jackson-datatype-jsr310 from 2.9.4 to 2.9.6.


Spring 1.5.10.RELEASE


Spring 2.0.3.RELEASE


lombok


1.16.14


1.18.0


jackson-datatype-jsr310


2.9.4


2.9.6



The JSON string -


"heading":"Validation failed","detail":"field must not be null"



The Class -


@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail

private final String heading;
private final String detail;
private String type;



Method call -


ErrorDetail errorDetail = asObject(jsonString, ErrorDetail.class);



The method used to deserialize -


import com.fasterxml.jackson.databind.ObjectMapper;
// more imports and class defination.

private static <T> T asObject(final String str, Class<T> clazz)
try
return new ObjectMapper().readValue(str, clazz);
catch (Exception e)
throw new RuntimeException(e);




Error -


java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.foo.bar.ErrorDetail` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)""heading":"Validation failed","detail":"field must not be null""; line: 1, column: 2]





Did you try to add constructer to ErrorDetail class?
– Tugrul
Jul 22 at 11:50




3 Answers
3



Lombok stopped generating @ConstructorProperties on constructors with version 1.16.20 (see changelog), because it might break Java 9+ applications that use modules. That annotation contains the names of the constructor's parameters (they are removed when compiling the class, so that's a workaround so that the parameter names still can be retrieved at runtime). Because the annotation is now not being generated by default, Jackson cannot map the field names to the constructor parameters.


@ConstructorProperties



Solution 1:
Use a @NoArgsConstructor and @Setter, but you will loose immutability (if that's important to you).


@NoArgsConstructor


@Setter



Update: Just @NoArgsConstructor and @Getter (without @Setter) may also work (because INFER_PROPERTY_MUTATORS=true). In this way, you can keep the class immutable, at least from regular (non-reflective) code.


@NoArgsConstructor


@Getter


@Setter


INFER_PROPERTY_MUTATORS=true



Solution 2:
Configure lombok to generate the annotations again, using a lombok.config file containing the line lombok.anyConstructor.addConstructorProperties = true. (If you are using modules, make sure java.desktop is on your module path.)


lombok.config


lombok.anyConstructor.addConstructorProperties = true


java.desktop



Solution 3:
Use Jackson's builder support in combination with lombok's @Builder, as described here.


@Builder





Thank you. The first option did the trick. The second one did not work though.
– JHS
Jul 22 at 13:02





Ad 2) Did you add the lombok.config to the root folder of your project? Also note that you have to clean and recompile after doing that.
– Jan Rieke
Jul 22 at 14:04



lombok.config



You want to deserialize a class which has final field. so u need to declare a constructor which contains final field to deserialize.


@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail

private final String heading;
private final String detail;
private String type;

@JsonCreator
public ErrorDetail(@JsonProperty("heading") String heading, @JsonProperty("detail") String detail)
this.heading = heading;
this.detail = detail;




and when deserialize with mapper need to MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS set this property false.


private static <T> T asObject(final String str, Class<T> clazz)
try
return new ObjectMapper().configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS,false).readValue(str, clazz);
catch (Exception e)
throw new RuntimeException(e);




Using @Data annotation is bad approach, in my opinion.
Please change @Data to @Getting , @Setter, @EqualsAndHashcode and so on ..


@Data


@Data


@Getting


@Setter


@EqualsAndHashcode



and write here please, if it will help.



update



I suggest, that @Data create @RequiredArgsConstructor, and it is constructor with final fields, and without private String type;


@Data


@RequiredArgsConstructor


private String type






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

Executable numpy error

PySpark count values by condition

Trying to Print Gridster Items to PDF without overlapping contents