Reputation: 964
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;
Upvotes: 9
Views: 7710
Reputation: 278
Although @blacktide solution looks fine I have found it not working for me. Maybe because of Scala not Java, maybe because of library versions. @blacktide code causes StackOverflow for me. I used intermediate wrapper class to avoid the issue. Tested for "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.11.3".
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.{DeserializationContext, JsonDeserializer, ObjectMapper}
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
final case class Wrapper(@JsonProperty("delivery") delivery:Delivery)
final case class Delivery(@JsonProperty("providerResponse") providerResponseWrapper: ProviderResponseWrapper) // field name provided to be read as "providerResponse"
@JsonDeserialize(using = classOf[ProviderResponseWrapperDeserializer])
final case class ProviderResponseWrapper(@JsonProperty("providerResponse") providerResponse: ProviderResponse)
final case class ProviderResponse(@JsonProperty("sqsRequestId") sqsRequestId: String, @JsonProperty("sqsMessageId") sqsMessageId: String)
final case class ProviderResponseWrapperDeserializer() extends JsonDeserializer[ProviderResponseWrapper] {
override def deserialize(jsonParser: JsonParser, deserializationContext: DeserializationContext): ProviderResponseWrapper =
ProviderResponseWrapper(new ObjectMapper().readValue(jsonParser.getText, classOf[ProviderResponse])) // mapper may be moved to the object
}
It outputs:
Wrapper(Delivery(ProviderResponseWrapper(ProviderResponse(308ee0c6-7d51-57b0-a472-af8e6c41be0b,88dd59eb-c34d-4e4d-bb27-7e0d226daa2a))))
Please pay attention to provide proper name for providerResponseWrapper using annotation.
Upvotes: 0
Reputation: 3191
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.
Upvotes: 1
Reputation: 12076
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);
Upvotes: 8