0

I have a JSON string like this :

 {
       "serviceName":"Data file "%s" was deleted successfully.",
       "serviceInstance":"esm-session-service"
     }

I am trying to map above JSON to object using ObjectMapper as below:

Message messageObject = objectMapper.readValue(messageJson, Message.class);

Below is stack trace output:

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('%' (code 37)): was expecting comma to separate Object entries
 at [Source: (String)"{"serviceName":"\"Data file \""%s"serviceInstance":"esm-session-service"}r""; line: 1, column: 33]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:663)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:561)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipComma(ReaderBasedJsonParser.java:2271)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextFieldName(ReaderBasedJsonParser.java:892)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:295)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
    at com.test.json.TestJsonObjectConversion.main(TestJsonObjectConversion.java:77)

I know problem is with "%s" in the JSON, I am not able to find any way to escape quotes in only "%s".

I am expecting below JSON:

{
  "serviceName":"Data file \"%s\" was deleted successfully.",
  "serviceInstance":"esm-session-service"
}

Thanks in advance.

Denis Ismailovski
  • 311
  • 1
  • 7
  • 15
Maninder
  • 171
  • 1
  • 3
  • 12

1 Answers1

0

The problem is stated as receiving an invalid JSON string from Elastic Search where double quotes are not escaped.

If you cannot find a correction by Elastic Search (looking for the latest version), a patch is in order:

Assuming key value pairs occupy a single line:

Since java 9:

String json = ...;
json = json.replaceAll(":\\s*\"(.*)\"",
        (m) -> {
            String value = m.group(1);
            value = value.replaceAll("(?!\\)\"", "\\\\\");
            return ":\"" + value + "\"";
        });

This will fill value with the longest sequence between double quotes. The negative lookahead (?!\\) checks that no backslash already precedes an inner double quote.

Maybe better would be to overall escape the string value by Apache Common Text StringEscapeUtils:

json = json.replaceAll(":\\s*\"(.*)\"",
        (m) -> ":\"" + StringEscapeUtils.escapeJson(m.group(1)) + "\"");

Prior to java 9 one would need a loop for the regex replace. If the key-value pairs are not on one line (like the value containing newlines) again the regex needs to do multiline, DOT_ALL.

The resulting JSON string can be passed, maybe via a StringReader.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138