Jackson does not support @JsonCreator in combination with builders. @JsonCreator basically says: The annotated method constructs a new instance, passing the JSON value as argument to its single parameter. That does not work for builders, because there is no such method that does it both (there are two separate methods, one for receiving a JSON value, and one for constructing the instance).
However, there is a simple workaround in your case without loosing immutability. Just put @JsonCreator on an all-args constructor as follows:
@Value
@AllArgsConstructor(onConstructor_ = {@JsonCreator})
public class Limit {
@JsonValue
String value;
}
You can keep the @Builder if you want to, but there is no need to do so.
[BUG] @Builder problem with classes consisting of one field and ObjectMapper
spring - Builder class does not have build method (name: 'build') - Jackson - Stack Overflow
[BUG] Jacksonized fails with Cannot construct instance
java - Cannot construct instance of - Jackson - Stack Overflow
The problem is that Jackson cannot deserialize the object value.
My solution was to add the following annotations to my class:
// constructor with no args
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
// constructor with all args
@AllArgsConstructor
// ignore unknown properties during deserialization
@JsonIgnoreProperties(ignoreUnknown = true)
My class ended up looking like this:
@Getter
@Builder
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyClass {
private boolean flag;
private boolean flag2;
private MyClassA objectA;
private MyClassB objectB;
}
If you want to read more on why should we use @NoArgsConstructor and @AllArgsConstructor together, here is a good answer.
Are You sure You always pass name and description to the class Builder?
I got the same error and In my case I was trying to to use a generated Builder to create an Object but I did not pass all of the arguments, so the generated method was not the one spring was looking for. It was searching the N+1 arguments method, but I was passing only N arguments. In this case it will look for a different method signature that can not find.
You cannot instantiate an abstract class, Jackson neither. You should give Jackson information on how to instantiate MyAbstractClass with a concrete type.
See this answer on stackoverflow: Jackson JSON library: how to instantiate a class that contains abstract fields
And maybe also see Jackson Polymorphic Deserialization
I was having this issue using lombok's @Data and @Builder annotations alone, which I replaced with:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
And it solved my problem.
Adding the @Jacksonized Lombok annotation to your class got it working for me:
@Getter
@Builder(builderClassName = "Builder")
@JsonIgnoreProperties(ignoreUnknown = true)
@Jacksonized
public class Test {
Per the Lombok documentation:
The
@Jacksonizedannotation is an add-on annotation for@Builderand@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@Builderor a@SuperBuilder; a warning is emitted otherwise.Without
@Jacksonized, you would have to customize your builder class(es). With@Jacksonized, you can simply write something like this to let Jackson use the generated builder:@Jacksonized @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class JacksonExample { private List<Foo> foos; }
Use @ConstructorProperties from Java 8 beans module:
import java.beans.ConstructorProperties;
@ConstructorProperties({"prop1","prop2"})
public CustomClass(String prop1, String prop2) {
this.prop1 = prop1;
this.prop2 = prop2;
}
So I have code with an object mapper to convert a String of JSON to an object:
And the JSON in question looks like so:
{
"address": "url",
"position": {
"positionType" : "type"
},
"id": "id",
"obj": "*"
}So the object I have for the outer set of parameters is:
public class Example {
private String address;
private Position position;
private String id;
private String id;
private String obj;
//getters and setters for each field
}(Note that I tried to do without the Position object and was able to convert the rest of the fields no problem on their own)
But with the Position object to cover the innermost fields from the JSON:
public class Position {
private String positionType;
public String getPositionType() {
return positionType;
}
public void setPositionType(String positionType) {
this.positionType = positionType;
}When I include this and try to convert the whole JSON from earlier, I keep getting an error:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `Position` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
Any ideas what I might be missing from Position? I can't understand since it worked with the outermost object on its own why the inclusion of the second object isn't working.
You can either add an @AllArgsConstructor annotation, because
@Buildergenerates an all-args constructor if there are no other constructors defined.
(Quoting @Andrew Tobilko)
Or set an attribute to @Builder : @Builder(toBuilder = true) This give you the functionality of a copy constructor.
@Builder(toBuilder = true)
class Foo {
// fields, etc
}
Foo foo = getReferenceToFooInstance();
Foo copy = foo.toBuilder().build();
When you provide your own constructor then Lombok doesn't create a constructor with all args that @Builder is using. So you should just add annotation @AllArgsConstructor to your class:
@Data //try to avoid as it's an anti-pattern
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RegistrationInfo {
//...
}
EDIT:
I just found a much better solution, add the ParanamerModule to the ObjectMapper:
mapper.registerModule(new ParanamerModule());
Maven:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-paranamer</artifactId>
<version>${jackson.version}</version>
</dependency>
The advantage against the ParameterNamesModule seems to be that the classes do not need to be compiled with the -parameters argument.
END EDIT
With Jackson 2.9.9 I tried to deserialize this simple POJO and came accros the same exception, adding a default constructor solved the problem:
POJO:
public class Operator {
private String operator;
public Operator(String operator) {
this.operator = operator;
}
public String getOperator() {
return operator;
}
}
ObjectMapper and Serialize/Deserialize:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.setVisibility(PropertyAccessor.CREATOR, Visibility.ANY);
String value = mapper.writeValueAsString(new Operator("test"));
Operator result = mapper.readValue(value, Operator.class);
JSON:
{"operator":"test"}
Exception:
com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot construct instance of `...Operator` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"operator":"test"}"; line: 1, column: 2]
Solution (POJO with default constructor):
public class Operator {
private String operator;
private Operator() {
}
public Operator(String operator) {
this();
this.operator = operator;
}
public String getOperator() {
return operator;
}
}
I observed this same issue. My issue was caused by me using the wrong JsonCreator type. I incorrectly used org.codehaus.jackson.annotate.JsonCreator, but should have used com.fasterxml.jackson.annotation.JsonCreator instead.
You need a constructor with all parameters:
public SampleRequest(String fromDate, String toDate) {
this.fromDate = fromDate;
this.toDate = toDate;
}
Or using @AllArgsConstructor or @Data from lombok.
In my case i was missing the No Args contructor
@Data
@AllArgsConstructor
@NoArgsConstructor
for those who are not using Lombok do add no args constructor in the mapping pojo
public ClassA() {
super();
// TODO Auto-generated constructor stub
}
also dont forget to add the Bean of Restemplate in main file if you are using the same