Cannot deserialize from Object value (no delegate- or property-based Creator) using Jackson
Solution 1
You have to consider few cases:
-
message
field inJSON
is primitiveString
. OnPOJO
level it is anMessageSubscription
object. -
message
value inJSON
contains unquoted property names which is illegal butJackson
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))
Solution 2
The message is pretty clear: (no Creators, like default construct, exist)
you need to add a no argument constructor to the class or the NoArgsConstructor
annotation:
@Data
public class DeserializeSubscription {
public DeserializeSubscription (){}
or
@NoArgsConstructor
@Data
public class DeserializeSubscription {
Scripta14
Updated on July 09, 2022Comments
-
Scripta14 almost 2 years
I'm trying to deserialise below
JSON
payload withJackson
:{"code":null,"reason":"subscription yet available","message":"{ Message:\"subscription yet available\", SubscriptionUID:\"46b62920-c519-4555-8973-3b28a7a29463\" }"}
but I'm getting this
JsonMappingException
:Cannot construct instance of `com.ids.utilities.DeserializeSubscription` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"code":null,"reason":"subscription yet available","message":"{ Message:\"subscription yet available\", SubscriptionUID:\"46b62920-c519-4555-8973-3b28a7a29463\" }"}"; line: 1, column: 2]
I've created two classes. The first class:
import lombok.Data; @Data public class DeserializeSubscription { private String code; private String reason; private MessageSubscription message; public DeserializeSubscription(String code, String reason, MessageSubscription message) { super(); this.code = code; this.reason = reason; this.message = message; }
and the second class
import lombok.Data; @Data public class MessageSubscription { private String message; private String subscriptionUID; public MessageSubscription(String message, String subscriptionUID) { super(); this.message = message; this.subscriptionUID = subscriptionUID; }
In the main class:
try { ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); DeserializeSubscription desSub=null; desSub=mapper.readValue(e.getResponseBody(), DeserializeSubscription.class); System.out.println(desSub.getMessage().getSubscriptionUID()); } catch (JsonParseException e1) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JsonMappingException e1) { System.out.println(e1.getMessage()); e.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e.printStackTrace(); }
I've found this solution but I didn't work it https://facingissuesonit.com/2019/07/17/com-fasterxml-jackson-databind-exc-invaliddefinitionexception-cannot-construct-instance-of-xyz-no-creators-like-default-construct-exist-cannot-deserialize-from-object-value-no-delega/
The jackson maven I'm using in my application
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.2</version> </dependency>
-
Scripta14 about 4 yearsSorry, I've tryied the first solution before and obtain the same result with tthe second solution
-
Jens about 4 years@Scripta14* the same result with tthe second solution* and what ist the result?
-
Scripta14 about 4 yearsThe same exception:
Cannot construct instance of `com.ids.utilities.DeserializeSubscription` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{"code":null,"reason":"subscription yet available","message":"{ Message:\"subscription yet available\", SubscriptionUID:\"46b62920-c519-4555-8973-3b28a7a29463\" }"}"; line: 1, column: 2]
-
Scripta14 about 4 yearsThanks a lot for your solution.. Unfortunately, I copied your code but I've got this error:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Unexpected end-of-input within/between Object entries at [Source: (String)"{ Message:"; line: 1, column: 3] (through reference chain: test.exatest.DeserializeSubscription["message"])
. I've used my json string -
Michał Ziober about 4 years@Scripta14, probably you have broken
JSON
payload. Also, have you enabledJsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES
feature? I have tested it for your payload and it works well. Which version ofJackson
do you use? -
Scripta14 about 4 yearsabove I wrote Jackson maven version that I'm using in my application. I've copied your code. The only on difference, I've used json string that I wrote above of this post.
-
Michał Ziober about 4 years@Scripta14, have you escaped
JSON
payload properly? Payload:"{\"code\":null,\"reason\":\"subscription yet available\",\"message\":\"{ Message:\\\"subscription yet available\\\", SubscriptionUID:\\\"46b62920-c519-4555-8973-3b28a7a29463\\\" }\"}"
-
Scripta14 about 4 yearsThanks a lot ...It's working well your json payload, It was missing some escape
-
Michał Ziober about 4 years@Scripta14, in case it works for you consider to accept and upvote my answer. How does accepting an answer work?