I need to convert the following JSON to Java object. The property providerResponse
in the JSON contains map of properties but they are escaped and wrapped in doubleQuotes. As a result, it does not deserialize the property providerResponse
into a Java object (it comes as String
). I use objectMapper.readValue(msgStr, classType)
to deserialize the JSON. The message is generated by AWS for SNS delivery status notifications and I don't have control to change the JSON message. Is it possible to configure ObjectMapper
to unescape the property and deserialize into a Java object instead of String
?
{
"delivery":{
"providerResponse":"{\"sqsRequestId\":\"308ee0c6-7d51-57b0-a472-af8e6c41be0b\",\"sqsMessageId\":\"88dd59eb-c34d-4e4d-bb27-7e0d226daa2a\"}"
}
}
@JsonProperty("providerResponse")
private String providerResponse;
You can escape String in Java by putting a backslash in double quotes e.g. " can be escaped as \" if it occurs inside String itself. This is ok for a small JSON String but manually replacing each double quote with an escape character for even a medium-size JSON is time taking, boring, and error-prone.
ObjectMapper; ObjectMapper objectMapper = new ObjectMapper(); objectMapper. configure(DeserializationFeature. FAIL_ON_UNKNOWN_PROPERTIES, false); This will now ignore unknown properties for any JSON it's going to parse, You should only use this option if you can't annotate a class with @JsonIgnoreProperties annotation.
In JSON the only characters you must escape are \, ", and control codes. Thus in order to escape your structure, you'll need a JSON specific function. As you might know, all of the escapes can be written as \uXXXX where XXXX is the UTF-16 code unit¹ for that character.
There doesn't seem to be a way to configure ObjectMapper
to handle this behavior by default. The solution is to create a custom JsonDeserializer
:
public class Wrapper {
public Delivery delivery;
}
public class Delivery {
@JsonDeserialize(using = ProviderResponseDeserializer.class)
public ProviderResponse providerResponse;
}
public class ProviderResponse {
public String sqsRequestId;
public String sqsMessageId;
}
public class ProviderResponseDeserializer extends JsonDeserializer<ProviderResponse> {
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public ProviderResponse deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return mapper.readValue(jsonParser.getText(), ProviderResponse.class);
}
}
Then you can deserialize the JSON by using your ObjectMapper
:
ObjectMapper mapper = new ObjectMapper();
Wrapper wrapper = mapper.readValue(JSON, Wrapper.class);
I faced this similar issue. This gets resolved if we define a constructor in ProviderResponse
which takes a single string argument (which is actually json) and then map the json in the constructor to the instance of ProviderResponse
and use this temp instance to initialise the properties.
public class Wrapper {
public Delivery delivery;
}
public class Delivery {
public ProviderResponse providerResponse;
}
public class ProviderResponse {
public String sqsRequestId;
public String sqsMessageId;
private static ObjectMapper objMapper = new ObjectMapper();
public ProviderResponse(String json) {
ProviderResponse temp = objMapper.readValue(json, ProviderResponse.class);
this.sqsMessageId = temp.sqsMessageId;
this.sqsRequestId = temp.sqsRequestId;
}
}
The key is to keep the ObjectMapper
instance and the its usage somewhere in your utility class and use it from there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With