Lombok 1.18.0 and Jackson 2.9.6 not working together
Edit: This answer is now a bit outdated: There is a new @Jacksonized
annotation, from https://projectlombok.org/features/experimental/Jacksonized, which takes care of much of the boilerplate in this answer.
The best way to make jackson and lombok play well together is to always make your DTO's immutable, and tell jackson to use the builder to deserialize into your objects.
Immutable objects are good idea for the simple reason that when fields cannot be modified in situ compilers can do much more aggressive optimisations.
In order to do this you need two annotations: JsonDeserialize, and JsonPojoBuilder.
Example:
@Builder
@Value // instead of @Data
@RequiredArgsConstructor
@NonNull // Best practice, see below.
@JsonDeserialize(builder = ErrorDetail.ErrorDetailBuilder.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {
private final String heading;
// Set defaults if fields can be missing, like this:
@Builder.Default
private final String detail = "default detail";
// Example of how to do optional fields, you will need to configure
// your object mapper to support that and include the JDK 8 module in your dependencies..
@Builder.Default
private Optional<String> type = Optional.empty()
@JsonPOJOBuilder(withPrefix = "")
public static final class ErrorDetailBuilder {
}
}
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.
Solution 1:
Use a @NoArgsConstructor
and @Setter
, but you will loose immutability (if that's important to you).
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.
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.) Clean and recompile after you added the lombok.config
file.
Solution 3:
Use Jackson's builder support in combination with lombok's (@Jacksonized
) @Builder
/@SuperBuilder
, as described in @Randakar answer to this question.
Solution 4:
When compiling with javac
(of Java 8 and above), append -parameters
to the command. This will store the parameter names of constructors and methods in the generated class files, so they can be retrieved via reflection.