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?
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With