Lombok 1.18.0 and Jackson 2.9.6 not working together
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.
Problem Jackson deserialization of JSON and Lombok constructor
You are missing @NoArgsConstructor.
@NoArgsConstructor
public class Text {
...
}
Jackson ObjectMapper default values with lombok on codhaus and fasterexml
The "codehaus" version of Jackson is the 1.x version of Jackson. Since 2.0, Jackson is located at "com.fasterxml.jackson". Without having tested it, it is very likely that the behavior simply (and intentionally) changed with Jackson 2.
However, as you found out by yourself, you can explicitly advise Jackson to use the no-args constructor when deserializing. You can also put that annotation on a lombok-generated constructor, so you do not have to write it manually:
@Data
@Builder
@EqualsAndHashCode
@NoArgsConstructor(onConstructor_ = @JsonCreator)
@AllArgsConstructor
public class CompanyRequest {
@Builder.Default
private String email = "";
private int company;
@Builder.Default
List<UserIdMapping> users = new ArrayList<>();
}
Make sure you use at least Lombok v1.18.2 so ensure the @Builder.Default
values are also set within this constructor.
Consider putting @Jacksonized @Builder
on the class if you want immutability and the builder to be the only way of creating instances (with at least Lombok v1.18.16):
@Jacksonized
@Builder
@Value
public class CompanyRequest {
@Builder.Default
private String email = "";
private int company;
@Singular
List<UserIdMapping> users;
}
Lombok + Jackson = MismatchedInputException
As mentioned in comments using
.userAddress(mapper.readValue(rs.getString(SqlConstants.TableUser.USER_ADDRESS),
User.UserAddress.class))
should work just fine at least it does for me. However after that change you might run into:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "house_number" ...
(instead of the original error) which will be fixed by small change to your UserAddressBuilder
:
@JsonProperty("house_number") // this is also needed to map correctly
public UserAddressBuilder houseNumber(String houseNumber) { ...
From Javadoc:
public T convertValue(Object fromValue, Class toValueType)
throws IllegalArgumentExceptionConvenience method for doing two-step conversion from given value, into instance of given value type. This is functionality equivalent to first serializing given value into JSON, then binding JSON data into value of given type, but may be executed without fully serializing into JSON. Same converters (serializers, deserializers) will be used as for data binding, meaning same object mapper configuration works
while readValue
is for reading from string, stream, reader into a object value. With convertValue(..)
you might need converters defined but in your case it is not needed.
Related Topics
Soap Request to Webservice with Java
How to Convert Timestamp to Date in Java
Possible to Use Two Java Classes with Same Name and Same Package
Observer Is Deprecated in Java 9. What Should We Use Instead of It
Capturing Browser Logs with Selenium Webdriver Using Java
Using Bufferedreader.Readline() in a While Loop Properly
Equivalent Function to C's "_Getch()" in Java
How to Change the Highlight Color of a Focused Jcombobox
Gson and Deserializing an Array of Objects with Arrays in It
Jce Cannot Authenticate the Provider Bc in Java Swing Application
Httpclient 4.0.1 - How to Release Connection
How to Create a New Packaging Type for Maven
Creating an X509 Certificate in Java Without Bouncycastle
How to Dynamically Create a Test Suite in Junit 4
Jtable + Sorting Specific Field
Websphere All Logs Are Going to Systemout.Log
How to Use Selenium Webdriver Without Informing the Document That It Is Controlled by Webdriver