No Creators, Like Default Construct, Exist): Cannot Deserialize from Object Value (No Delegate- or Property-Based Creator

No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator

Reason: This error occurs because jackson library doesn't know how to create your model which doesn't have an empty constructor and the model contains constructor with parameters which didn't annotated its parameters with @JsonProperty("field_name"). By default java compiler creates empty constructor if you didn't add constructor to your class.

Solution:
Add an empty constructor to your model or annotate constructor parameters with @JsonProperty("field_name")

If you use a Kotlin data class then also can annotate with @JsonProperty("field_name") or register jackson module kotlin to ObjectMapper.

You can create your models using http://www.jsonschema2pojo.org/.

No Creators Exist: Cannot Deserialize

If there is no constructors that is annotated with @JsonCreator, by default, Jackson needs a default no-args constructor in order to parse the JSON into POJO or bean classes. That is why when you add a default constructor, it will work fine.

And if you don't actually need the usage of the default constructor, just add it for Jackson only, you can set it to private, protected or package-protected. Jackson is still able to fill all the fields via reflection.

Regarding the no delegate- or property-based Creator, they are constructors that is annotated with @JsonCreator. In Jackson, there are 2 types of Creator/JsonCreator which are delegate-based Creator and property-based Creator.

Delegate-based creators take just one argument, which is NOT annotated with @JsonProperty. Type of that property is used by Jackson to bind the whole JSON value (JSON Object, array or scalar value), to be passed as value of that one argument.

Property-based creators take one or more arguments; all of which MUST be annotated with @JsonProperty, to specify JSON name used for property. They can only be used to bind data from JSON Objects; and each parameter represents one property of the JSON Object; type of property being used for binding data to be passed as that parameter when calling creator.

You can read for more details about these 2 creators in the article below.
http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html

Cannot deserialize from Object value (no delegate- or property-based Creator) using Jackson

You have to consider few cases:

  • message field in JSON is primitive String. On POJO level it is an MessageSubscription object.
  • message value in JSON contains unquoted property names which is illegal but Jackson handles them as well.
  • If constructor does not fit to JSON we need to configure it using annotations.

To handle unquoted names we need to enable ALLOW_UNQUOTED_FIELD_NAMES feature. To handle mismatch between JSON payload and POJO we need to implement custom deserialiser for MessageSubscription class.

Custom deserialiser could look like this:

class MessageSubscriptionJsonDeserializer extends JsonDeserializer<MessageSubscription> {
@Override
public MessageSubscription deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
final String value = p.getValueAsString();
final Map<String, String> map = deserializeAsMap(value, (ObjectMapper) p.getCodec(), ctxt);

return new MessageSubscription(map.get("Message"), map.get("SubscriptionUID"));
}

private Map<String, String> deserializeAsMap(String value, ObjectMapper mapper, DeserializationContext ctxt) throws IOException {
final MapType mapType = ctxt.getTypeFactory().constructMapType(Map.class, String.class, String.class);
return mapper.readValue(value, mapType);
}
}

Now, we need to customise DeserializeSubscription's constructor:

@Data
class DeserializeSubscription {

private String code;
private String reason;
private MessageSubscription message;

@JsonCreator
public DeserializeSubscription(
@JsonProperty("code") String code,
@JsonProperty("reason") String reason,
@JsonProperty("message") @JsonDeserialize(using = MessageSubscriptionJsonDeserializer.class) MessageSubscription message) {
super();
this.code = code;
this.reason = reason;
this.message = message;
}
}

Example how to use it:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.MapType;
import lombok.Data;

import java.io.File;
import java.io.IOException;
import java.util.Map;

public class JsonPathApp {

public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();

ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
mapper.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);

DeserializeSubscription value = mapper.readValue(jsonFile, DeserializeSubscription.class);
System.out.println(value);
}
}

For provided JSON payload above example prints:

DeserializeSubscription(code=null, reason=subscription yet available, message=MessageSubscription(message=subscription yet available, subscriptionUID=46b62920-c519-4555-8973-3b28a7a29463))

Cannot construct instance of `com.domain.User` (no Creators, like default constructor, exist): cannot deserialize from Object value

I could reproduce the exception. Then I added an all-args constructor with each parameter annotated with the right @JsonProperty.

@JsonCreator
public User(
@JsonProperty("email") String email,
@JsonProperty("password") String password,
@JsonProperty("firstName") String firstName,
@JsonProperty("lastName") String lastName,
@JsonProperty("gender") String gender,
@JsonProperty("registrationTime") Instant registrationTime){
super();
this.email = email;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.registrationTime = registrationTime;
}

Now, it creates the instance, but I get other mapping errors (Unrecognized field "given_name") which you should be able to resolve.



Related Topics



Leave a reply



Submit