Flatten a hashmap derived from a json string in Java

Simplexity :

I have through various reasons ended up in a situation where I need to deserialize a json object from Fable F# in android studio with java. The string is as follows:

{"MainForm":{"OriginMerd":{"id":"onMggagerd","number":5,"tests":{"Blod":{"blodid":"1","glucose":52}}}}}

the code:

    Stream<Map.Entry<String, String>> flatten(Map<String, Object> map) 
    {
        return map.entrySet()
                .stream()
                .flatMap(this::extractValue);
    }

    Stream<Map.Entry<String, String>> extractValue(Map.Entry<String, Object> entry) {
        if (entry.getValue() instanceof String) {
            return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(), (String) entry.getValue()));
        } else if (entry.getValue() instanceof Map) {
            return flatten((Map<String, Object>) entry.getValue());
        }
        return null;
    }

    @ReactMethod
    public void testFunc(String jsonString, Callback cb){
        Map<String,Object> map = new HashMap<>();

        ObjectMapper mapper = new ObjectMapper();

        try {
            //convert JSON string to Map
            map = mapper.readValue(String.valueOf(jsonString), new TypeReference<Map<String, Object>>() {
            });


            Map<String, String> flattenedMap = flatten(map)
                     .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

            for (Map.Entry<String, String> entry : flattenedMap.entrySet()) {
                Log.e("flatmap",entry.getKey() + "/" + entry.getValue());

                //System.out.println(entry.getKey() + "/" + entry.getValue());
            }
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Log.e("JSONSTRING", jsonString);

        cb.invoke("OK");
    }

First I figured I'd make it into a map with object mapper as such I used the object mapper to get a map of then I followed this approach How to Flatten a HashMap?

However the issue with this is that the result only gives me the orginMerd id and the blodid, not the number or glucose fields. Is there a elegant way to achieve this? I am unfortunately not very well versed in Java.

davidxxx :

You handle only the cases for values of type string or map of your json :

if (entry.getValue() instanceof String) {
    return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(), (String) entry.getValue()));
} else if (entry.getValue() instanceof Map) {
    return flatten((Map<String, Object>) entry.getValue());
}

To get number or glucose entries, you should also handle the Number type with Long or Integer according to what you get from the JSON deserialization.

The problem with this approach is that Integer and Long are not String and actually you map the json entries to Stream<Map.Entry<String, String>>.
Putting numbers in String variables is possible with toString() :

For example to handle both number and string :

final String value = entry.getValue();
if (value instanceof String || value instanceof Number) {
    return Stream.of(new AbstractMap.SimpleEntry(entry.getKey(),
                                                value.toString()));
}
else if (value instanceof Map) {
    return flatten((Map<String, Object>) value);
}
// you may return null but you will at least log something
else {
     LOGGER.warn("field with key {} and value {} not mapped", entry.getKey(), value);
     return null;
}

But it will also make the content of your Map unclear requiring some checks before using it.
Similarly using a generic type like Stream<Map.Entry<String, Object>> will create a similar issue.

So I think that you could consider using a specific class to represent your model and use it during deserialization.

Foo foo = mapper.readValue(String.valueOf(jsonString), Foo.class);

where Foo is a class describing the expected structure.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=123453&siteId=1