I'm trying to deserialise below JSON
payload with Jackson
:
{"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>
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.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))