Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to efficiently map a org.json.JSONObject to a POJO?

This question must have been asked before, but I couldn't find it.

I'm using a 3rd party library to retrieve data in JSON format. The library offers the data to me as a org.json.JSONObject. I want to map this JSONObject to a POJO (Plain Old Java Object) for simpler access/code.

For mapping, I currently use the ObjectMapper from the Jackson library in this way:

JSONObject jsonObject = //... ObjectMapper mapper = new ObjectMapper(); MyPojoClass myPojo = mapper.readValue(jsonObject.toString(), MyPojoClass.class); 

To my understanding, the above code can be optimized significantly, because currently the data in the JSONObject, which is already parsed, is again fed into a serialization-deserialization chain with the JSONObject.toString() method and then to the ObjectMapper.

I want to avoid these two conversions (toString() and parsing). Is there a way to use the JSONObject to map its data directly to a POJO?

like image 997
Daniel S. Avatar asked Dec 12 '13 04:12

Daniel S.


People also ask

What is the difference between org JSON JSON object and org JSON simple JSON object?

simple package contains important classes like JSONValue, JSONObject, JSONArray, JsonString and JsonNumber. We need to install the json-simple. jar file to execute a JSON program whereas org. json library has classes to parse JSON for Java.

What is the difference between MAP and JSON object?

A JSONObject is an unordered collection of name/value pairs whereas Map is an object that maps keys to values. A Map cannot contain duplicate keys and each key can map to at most one value. We need to use the JSON-lib library for serializing and de-serializing a Map in JSON format.


1 Answers

Since you have an abstract representation of some JSON data (an org.json.JSONObject object) and you're planning to use the Jackson library - that has its own abstract representation of JSON data (com.fasterxml.jackson.databind.JsonNode) - then a conversion from one representation to the other would save you from the parse-serialize-parse process. So, instead of using the readValue method that accepts a String, you'd use this version that accepts a JsonParser:

JSONObject jsonObject = //... JsonNode jsonNode = convertJsonFormat(jsonObject); ObjectMapper mapper = new ObjectMapper(); MyPojoClass myPojo = mapper.readValue(new TreeTraversingParser(jsonNode), MyPojoClass.class); 

JSON is a very simple format, so it should not be hard to create the convertJsonFormat by hand. Here's my attempt:

static JsonNode convertJsonFormat(JSONObject json) {     ObjectNode ret = JsonNodeFactory.instance.objectNode();      @SuppressWarnings("unchecked")     Iterator<String> iterator = json.keys();     for (; iterator.hasNext();) {         String key = iterator.next();         Object value;         try {             value = json.get(key);         } catch (JSONException e) {             throw new RuntimeException(e);         }         if (json.isNull(key))             ret.putNull(key);         else if (value instanceof String)             ret.put(key, (String) value);         else if (value instanceof Integer)             ret.put(key, (Integer) value);         else if (value instanceof Long)             ret.put(key, (Long) value);         else if (value instanceof Double)             ret.put(key, (Double) value);         else if (value instanceof Boolean)             ret.put(key, (Boolean) value);         else if (value instanceof JSONObject)             ret.put(key, convertJsonFormat((JSONObject) value));         else if (value instanceof JSONArray)             ret.put(key, convertJsonFormat((JSONArray) value));         else             throw new RuntimeException("not prepared for converting instance of class " + value.getClass());     }     return ret; }  static JsonNode convertJsonFormat(JSONArray json) {     ArrayNode ret = JsonNodeFactory.instance.arrayNode();     for (int i = 0; i < json.length(); i++) {         Object value;         try {             value = json.get(i);         } catch (JSONException e) {             throw new RuntimeException(e);         }         if (json.isNull(i))             ret.addNull();         else if (value instanceof String)             ret.add((String) value);         else if (value instanceof Integer)             ret.add((Integer) value);         else if (value instanceof Long)             ret.add((Long) value);         else if (value instanceof Double)             ret.add((Double) value);         else if (value instanceof Boolean)             ret.add((Boolean) value);         else if (value instanceof JSONObject)             ret.add(convertJsonFormat((JSONObject) value));         else if (value instanceof JSONArray)             ret.add(convertJsonFormat((JSONArray) value));         else             throw new RuntimeException("not prepared for converting instance of class " + value.getClass());     }     return ret; } 

Note that, while the Jackson's JsonNode can represent some extra types (such as BigInteger, Decimal, etc) they are not necessary since the code above covers everything that JSONObject can represent.

like image 174
mgibsonbr Avatar answered Oct 09 '22 10:10

mgibsonbr