Search code examples
javajsonspringspring-bootjson-deserialization

Parsing dynamic JSON values to Java objects


In my application I have lot of overviews (tables) with sorting and filtering capabilities. And becuase the different column can hold different value type (strings, numbers, dates, sets, etc.) the filter for these columns also can bring different values. Let me show you few examples (converted to JSON already as is sent to server via REST request):

For simple string value it is like:

{"<column_name>":"<value>"}

For number and date column the filter looks like:

{"<column_name>":[{"operator":"eq","value":"<value>"}]}
{"<column_name>":[{"operator":"eq","value":"<value1>"},{"operator":"gt","value":"<value2>"}]}

For set the filter looks like

{"<column_name>":["<value1>","<value2>"(,...)]}

Now I need to parse that JSON within a helper class that will build the WHERE clause of SQL query. In PHP this is not a problem as I can call json_decode and then simply check whether some value is array, string or whatever else... But how to do this simply in Java?

So far I am using Spring's JsonJsonParser (I didn't find any visible difference between different parsers coming with Spring like Jackson, Gson and others).

I was thinking about creating an own data object class with three different constructors or having three data object classes for all of the three possibilities, but yet I have no clue how to deal with the value returned for column_name after the JSON is parsed by parser...

Simply looking on the examples it gives me three possibilities:

  1. Map<String, String>
  2. Map<String, Map<String, String>>
  3. Map<String, String[]>

Any idea or clue?


Solution

  • You'll have to check the type of the values in runtime. You can work with a Map<String, Object> or with JsonNode.

    Map<String, Object>

    JsonParser parser = JsonParserFactory.getJsonParser();
    Map<String, Object> map = parser.parseMap(str);
    Object filterValue = filter.get("<column_name>");
    if (filterValue instanceof String) {
      // str is like "{\"<column_name>\":\"<value>\"}"
    } else if (filterValue instanceof Collection) {
      for (Object arrayValue : (Collection<Object>) filterValue) {
        if (arrayValue instanceof String) {
          // str is like "{\"<column_name>\":[\"<value1>\",\"<value2>\"]}"
        } else if (arrayValue instanceof Map) {
          // str is like "{\"<column_name>\":[{\"operator\":\"eq\",\"value\":\"<value>\"}]}"
        }
      }
    }
    

    JsonNode

    ObjectMapper mapper = new ObjectMapper();
    JsonNode filter = mapper.readTree(str);
    JsonNode filterValue = filter.get("<column_name>");
    if (filterValue.isTextual()) {
      // str is like "{\"<column_name>\":\"<value>\"}"
    } else if (filterValue.isArray()) {
      for (JsonNode arrayValue : filterValue.elements()) {
        if (arrayValue.isTextual()) {
          // str is like "{\"<column_name>\":[\"<value1>\",\"<value2>\"]}"
        } else if (arrayValue.isObject()) {
          // str is like "{\"<column_name>\":[{\"operator\":\"eq\",\"value\":\"<value>\"}]}"
        }
      }
    }