Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON to Java object deserialization with escaped properties

Tags:

java

json

jackson

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;
like image 326
user1573133 Avatar asked Apr 06 '16 21:04

user1573133


People also ask

How do you escape JSON in Java?

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.

How do I ignore properties in ObjectMapper?

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.

How do I escape a character in JSON?

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.


2 Answers

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);
like image 77
blacktide Avatar answered Nov 14 '22 23:11

blacktide


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.

like image 31
mantri Avatar answered Nov 14 '22 23:11

mantri