Search code examples
javaspring-bootjacksongsonjson-deserialization

Replace usage of new Gson().fromJson() with com.fasterxml.jackson.databind.ObjectMapper covering all the cases


Currently we are using Gson to convert a JSON String to Map<String, String>. It is required to eliminate use of Gson completely and replace it with ObjectMapper.

Currently if we are to convert following Json String to a Map<String, String>

"{"jwt":abc.def.ghi}"

Note that the value against the key "jwt" is not a string.

String jsonString = "{\"jwt\":abc.def.ghi}";
Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> tokens = new Gson().fromJson(jsonString, type);

Gson successfully converts it to

tokens = {"jwt":"abc.def.ghi"}

Corresponding Code using ObjectMapper:

Map<String, String> tokens = objectMapper.readValue(jsonString, new TypeReference<>() {});

When tried using ObjectMapper, following exception is thrown:

com.fasterxml.jackson.core.JsonParseException Unrecognised token 'abc.def.ghi' found ....

The issue is that unlike Gson, ObjectMapper is not able to parse abc.def.ghi to "abc.def.ghi".

What should be my correct approach to achieve the required result.

I have tried objectMapper.writeValueAsString() before passing it to the readValue(). Still no progress.


Solution

  • A simple; naïve solution would be to use a regular expression to fix the offending JSON:

    Pattern: (?<=":\s?)(?<unquoted>[^\{\}"]+)(?=,?)

    This pattern includes a positive lookbehind that checks for a preceding quote. followed by a colon and an optional space. This would be a potential key/prop.

    import java.util.Map;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class Deserializer {
    
        private static final ObjectMapper objectMapper;
        private static final TypeReference<Map<String, String>> mapType;
    
        static {
            objectMapper = new ObjectMapper();
            mapType = new TypeReference<Map<String, String>>() { };
        }
    
        public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
            String invalidJsonString = "{\"jwt\":abc.def.ghi}";
            String jsonString = fixUnquotedJsonValues(invalidJsonString);
            Map<String, String> tokens = objectMapper.readValue(jsonString, mapType);
    
            System.out.println(tokens);
        }
    
        public static String fixUnquotedJsonValues(String invalidJson) {
            return invalidJson.replaceAll(
                    "(?<=\\\":\\s?)(?<unquoted>[^\\{\\}\\\"]+)(?=,?)",
                    "\"${unquoted}\"");
        }
    }