Jackson: understand if source JSON is an array or an object - java

Parsing JSON in Jackson library would require:
for an object
MapType hashMapType = typeFactory.constructMapType(HashMap.class, String.class, Object.class);
Map<String, Object> receivedMessageObject = objectMapper.readValue(messageBody, hashMapType);
for an array of objects
Map[] receivedMessage = objectMapper.readValue(messageBody, HashMap[].class)
What would be the best way to check whether I have array or object in messageBody, in order to route to the correct parsing? Is it just to directly check for array token in MessageBody?

An option is just to treat everything that might be an array as an array. This is often most convenient if your source JSON has just been auto-transformed from XML or has been created using an XML-first library like Jettison.
It's a sufficiently common use case that there's a Jackson switch for this:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
You can then just deserialize a property into a collection type, regardless of whether it's an array or an object in the source JSON.

If you want to know whether your input is an array or an object, you can simply use the readTree method. A simple example:
ObjectMapper mapper = new ObjectMapper();
String json1 = "{\"key\": \"value\"}";
String json2 = "[\"key1\", \"key2\"]";
JsonNode tree1 = mapper.readTree(json1);
System.out.println(tree1.isArray());
System.out.println(tree1.isObject());
JsonNode tree2 = mapper.readTree(json2);
System.out.println(tree2.isArray());
System.out.println(tree2.isObject());
If you want to be able to deserialize to multiple types, have a look at Polymorphic Deserialization

This is what I did based on the answer from #ryanp :
public class JsonDataHandler {
public List<MyBeanClass> createJsonObjectList(String jsonString) throws JsonMappingException, JsonProcessingException {
ObjectMapper objMapper = new ObjectMapper();
objMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
List<MyBeanClass> jsonObjectList = objMapper.readValue(jsonString, new TypeReference<List<MyBeanClass>>(){});
return jsonObjectList;
}
}

Related

GSON - remove JSON data from JSON object

I'm looking to remove part of a JSON object, at the moment I only seem to be able to return the whole object.
JSON format:
{"blobJson":"{\"sensorID\":\"111122\",\"width\":32,\"height\":31,\"frameData\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}","deviceMfg":2,"eventCode":101,"sensorClass":1,"sensorUUID":"111122","timeStamp":1.53907307310099994E18,"uID":"111122_1_2"}
I'm looking to remove the [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] part of the JSON.
At the moment I'm using the following code:
JsonParser jp = new JsonParser(); //from gson
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent()));
JsonObject rootobj = root.getAsJsonObject();
System.out.println(rootobj);
This is outputting the following JSON:
{"blobJson":"","deviceMfg":-1,"eventCode":-1,"sensorClass":-1,"sensorUUID":"","timeStamp":0.0,"uID":"_-1_-1"}
If you want to remove the framedata key and value from the string. You can use the org.json.JSONObject as shown below:
JSONObject jo1 = new JSONObject("{\"blobJson\":{\"sensorID\":\"111122\",\"width\":32,\"height\":31,\"frameData\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"deviceMfg\":2,\"eventCode\":101,\"sensorClass\":1,\"sensorUUID\":\"111122\",\"timeStamp\":1.53907307310099994E18,\"uID\":\"111122_1_2\"}");
jo1.getJSONObject("blobJson").remove("frameData");
If you want to retain the key framedata but want only the value to be replace with [] then do the following:
JSONObject jo1 = new JSONObject("{\"blobJson\":{\"sensorID\":\"111122\",\"width\":32,\"height\":31,\"frameData\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},\"deviceMfg\":2,\"eventCode\":101,\"sensorClass\":1,\"sensorUUID\":\"111122\",\"timeStamp\":1.53907307310099994E18,\"uID\":\"111122_1_2\"}");
jo1.getJSONObject("blobJson").put("frameData", "[]");
You can use ObjectMapper from com.fasterxml.jackson.databind but then you require the corresponding class also with all the member variables corresponding to the json keys. In the above approach you can directly manipulate the Json String.
String stringifyRequest="{"blobJson":"{\"sensorID\":\"111122\",\"width\":32,\"height\":31,\"frameData\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}","deviceMfg":2,"eventCode":101,"sensorClass":1,"sensorUUID":"111122","timeStamp":1.53907307310099994E18,"uID":"111122_1_2"}";
final ObjectMapper mapper = new ObjectMapper();
"Yourpojoclass" investmentResponse = mapper.readValue(stringifyRequest, "Yourpojoclass".class);
here "Yourpojoclass" would be your class which consists string field parameter:
Now set your frameData value null and make your pojo class #JsonInclude(value=Include.NON_NULL)
and then convert it again in json.

Annotation to make Jackson interpret field either as JSON array or JSON object [duplicate]

Is there a way to make Jackson interpret single JSON object as an array with one element and vice versa?
Example, I have 2 slightly different formats of JSON, I need both to map to same Java object:
Format A (JSON array with one element):
points : [ {
date : 2013-05-11
value : 123
}]
Format B (JSON object, yes I know it looks "wrong" but it's what I'm given):
points : {
date : 2013-05-11
value : 123
}
Target Java object that both of the above should convert to:
//Data.java
public List<Point> points;
//other members omitted
//Point.java
class Point {
public String date;
public int value;
}
Currently, only A will parse properly to Data. I want avoid directly tampering with the JSON itself. Is there some configuration in Jackson I can tamper with in order to make it accept B ?
Try with DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY - it should work for you.
Example:
final String json = "{\"date\" : \"2013-05-11\",\"value\" : 123}";
final ObjectMapper mapper = new ObjectMapper()
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
final List<Point> points = mapper.readValue(json,
new TypeReference<List<Point>>() {});
The Jackson 1.x-compatible version uses DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY. So the above answer changes to:
final String json = "{\"date\" : \"2013-05-11\",\"value\" : 123}";
final ObjectMapper mapper = new ObjectMapper()
.enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
final List<Point> points = mapper.readValue(json,
new TypeReference<List<Point>>() {
});
System.out.println(points);
Can solve the above problem by this code is given below, this works
final ObjectMapper objectMapper = new
ObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
try {
String jsonInString = objectMapper.writeValueAsString(products.get(j));
InventoryParser inventoryParser = objectMapper.readValue(jsonInString,
InventoryParser.class);
System.out.println(inventoryParser.getId());
}
catch (IOException e)
{
e.printStackTrace();
}
"InventoryParser" is a POJO Class.
"products.get(j)" is JSON String.

Jackson deserialize json string with "pseudo array" of objects

I'm trying to read data from this API https://coinmarketcap.com/api/
For this endpoint https://api.coinmarketcap.com/v2/ticker/.
I'm having issues mapping the data field to a POJO. The field really contains an array of objects but in terms of the json it's not really defined as an array.
i.e. instead of
data: [{"id":"1","name":"some object"},{"id":"5","name":"another object"},...]
the json has named fields like so
data: {"1":{"id":"1","name":"some object"},"5":{"id":"5","name":"another object"},...}
I can manually parse this using
objectMapper.readTree(new URL("https://api.coinmarketcap.com/v2/ticker/"));
but is there a way automatically map these to a List?
You can parse it into a map (as #teppic said) and then get the map values as a list.
To deserialize into a map, you can see the answer from this question: Deserializing into a HashMap of custom objects with jackson
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, Theme.class);
HashMap<String, Theme> map = mapper.readValue(json, mapType);
Assuming you have a class called Item with the id and name fields, you can do this:
String json = "{\"1\":{\"id\":\"1\",\"name\":\"some object\"},\"5\":{\"id\":\"2\",\"name\":\"another object\"}}";
ObjectMapper mapper = new ObjectMapper();
// create your map type <String, Item>
TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, Item.class);
HashMap<String, Item> map = mapper.readValue(json, mapType);
// get the list
List<Item> list = new ArrayList<Item>(map.values());
System.out.println(list);
Output:
[Item [id=1, name=some object], Item [id=2, name=another object]]
Your other option would be a custom deserializer, or reading the tree as you mentioned.
try this
String json = "[{\"name\":\"Steve\",\"lastname\":\"Jobs\"}]";
JsonArray jArray = (JsonArray)new JsonParser().parse(json);
String sName = jArray.get(0).getAsJsonObject().get("name").getAsString());
String sLastName = jArray.get(0).getAsJsonObject().get("lastname").getAsString());
see you later.

How to convert List <JSONObject> to Json String in java (com.amazonaws.util.json.JSONObject)

com.amazonaws.util.json.JSONObject
Below is the List, i want to convert it into json string.
List<JSONObject> jsonObjlist is
[{"Attribute":"EmailAddress","Value":"abc#yahoo.com"}, {"Attribute":"Source","Value":"Missing_Fixed"}, {"Attribute":"mx_Lead_Status","Value":"Registered User"}, {"Attribute":"mx_Age","Value":""}, {"Attribute":"mx_LoginID","Value":"abc#yahoo.com"}, {"Attribute":"mx_Registration_Source","Value":"EMAIL"}]
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
String arrayToJson = objectMapper.writeValueAsString(jsonObjlist);
Output i get is
[{"map":{"Attribute":"EmailAddress","Value":"abc#yahoo.com"}},{"map":{"Attribute":"Source","Value":"Missing_Fixed"}},{"map":{"Attribute":"mx_Lead_Status","Value":"Registered User"}},{"map":{"Attribute":"mx_Age","Value":""}},{"map":{"Attribute":"mx_LoginID","Value":"abc#yahoo.com"}},{"map":{"Attribute":"mx_Registration_Source","Value":"EMAIL"}}]
Desired out put is
"[{"Attribute":"EmailAddress","Value":"abc#yahoo.com"}, {"Attribute":"Source","Value":"Missing_Fixed"}, {"Attribute":"mx_Lead_Status","Value":"Registered User"}, {"Attribute":"mx_Age","Value":""}, {"Attribute":"mx_LoginID","Value":"abc#yahoo.com"}, {"Attribute":"mx_Registration_Source","Value":"EMAIL"}]"
You should convert your list to a JSON Array, and just use its toString() function:
JSONArray myArray = new JSONArray(jsonObjlist);
// ...
String arrayToJson = myArray.toString(2);
The int parameter specifies the indent factor to use for formatting.
You can also direct use
String jsonString = new ObjectMapper().writeValueAsString(jsonObjectList)
To get the desired ouptput
Here is the small example
List<JSONObject> jsons = new ArrayList<>();
jsons.add(new JSONObject(ImmutableMap.of("Attribute", "EmailAddress", "Value", "abc#yahoo.com")));
jsons.add(new JSONObject(ImmutableMap.of("Attribute1", "EmailAddress3", "Value1", "abc#yahoo.com1")));
System.out.println(new ObjectMapper().writeValueAsString(jsons));
The output is
[{"Value":"abc#yahoo.com","Attribute":"EmailAddress"},{"Attribute1":"EmailAddress3","Value1":"abc#yahoo.com1"}]
I suspect there are some toString() method in any object that you have override?

Java boon JSON parser removing null values from output

I have a small function which takes an input JSON string, parses it using boon into a Map, replaces a value for a particular key, returns back the JSON string of the modified Map.
The code is as follows:
// inputJson = {"key3":"A","key2":"B","key1":null,"keyX":[{"x":2019,"y":123,"z":456},{"x":2017,"y":234,"z":345},{"x":2018,"y":456,"z":567}]}
private static String sorter(String inputJson) {
JsonParserAndMapper mapper = new JsonParserFactory().strict().create();
Map<String, Object> map = mapper.parseMap(inputJson);
List<?> l1 = (List<?>) map.get("keyX");
sort(l1, Sort.sortBy("x"));
map.replace("keyX", l1);
for (String x: map.keySet())
System.out.println(map.get(x));
String outputJson = toJson(map); // problem seems to be here
return outputJson
// outputJson = {"key2":"B","key3":"A","keyX":[{"x":2017,"y":234,"z":345},{"x":2018,"y":456,"z":567},{"x":2019,"y":123,"z":456}]}
The problem is, when I do toJson(map) it removes the key with null values. So, if inputJson contains a key with a null value, it doesn't appear in the output. (Notice: key1 is missing in the output)
How can I parse this without losing the null fields?
Using toJson you are using a default serialiser factory. From boon source code:
public class JsonFactory {
private static ObjectMapper json = JsonFactory.create();
public static ObjectMapper create () {
JsonParserFactory jsonParserFactory = new JsonParserFactory();
jsonParserFactory.lax();
return new ObjectMapperImpl(jsonParserFactory, new JsonSerializerFactory());
}
....
)
Instead of using toJson try using a serialiser factory with includeNulls()
JsonSerializer factory = new JsonSerializerFactory().includeNulls().create();

Categories