Mapping Json Array to POJO using Jackson - java

I have a JSON array of the form:
[
[
1232324343,
"A",
"B",
3333,
"E"
],
[
12345424343,
"N",
"M",
3133,
"R"
]
]
I want to map each element of the parent array to a POJO using the Jackson library. I tried this:
ABC abc = new ABC();
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(data).get("results");
if (jsonNode.isArray()) {
for (JsonNode node : jsonNode) {
String nodeContent = mapper.writeValueAsString(node);
abc = mapper.readValue(nodeContent,ABC.class);
System.out.println("Data: " + abc.getA());
}
}
where ABC is my POJO class and abc is the object but I get the following exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.demo.json.model.ABC
EDIT:
My POJO looks like this:
class ABC{
long time;
String a;
String b;
int status;
String c;
}
Can someone suggest a solution for this?
EDIT 2: After consulting a lot of answers on StackOverflow and other forums, I came across one solution. I mapped the returned value of readValue() method into an array of POJO objects.
ABC[] abc = mapper.readValue(nodeContent, ABC[].class);
But now I am getting a separate exception
Can not construct instance of ABC: no long/Long-argument constructor/factory method to deserialize from Number value (1552572583232)
I have tried the following but nothing worked:
1. Forcing Jackson to use ints for long values using
mapper.configure(DeserializationFeature.USE_LONG_FOR_INTS, true);
2. Using wrapper class Long instead of long in the POJO
Can anyone help me with this?

You can use ARRAY shape for this object. You can do that using JsonFormat annotation:
#JsonFormat(shape = Shape.ARRAY)
class ABC {
And deserialise it:
ABC[] abcs = mapper.readValue(json, ABC[].class);
EDIT after changes in question.
You example code could look like this:
JsonNode jsonNode = mapper.readTree(json);
if (jsonNode.isArray()) {
for (JsonNode node : jsonNode) {
String nodeContent = mapper.writeValueAsString(node);
ABC abc = mapper.readValue(nodeContent, ABC.class);
System.out.println("Data: " + abc.getA());
}
}
We can use convertValue method and skip serializing process:
JsonNode jsonNode = mapper.readTree(json);
if (jsonNode.isArray()) {
for (JsonNode node : jsonNode) {
ABC abc = mapper.convertValue(node, ABC.class);
System.out.println("Data: " + abc.getA());
}
}
Or even:
JsonNode jsonNode = mapper.readTree(json);
ABC[] abc = mapper.convertValue(jsonNode, ABC[].class);
System.out.println(Arrays.toString(abc));

Your json does not map to the pojo that you have defined. For the pojo that you have defined, the json should be of the form below.
{
"time:1232324343,
"a":"A",
"b":"B",
"status":3333,
"c":"E"
}

Related

How to get json value with jackson?

String url = "https://ko.wikipedia.org/w/api.php?action=query&format=json&list=search&srprop=sectiontitle&srlimit=1&srsearch=grand-theft-auto-v";
String test = restTemplate.getForObject(url, String.class);
Map<String, String> testToJson = objectMapper.readValue(test, Map.class);
testToJson is:
{
batchcomplete: "",
continue: {
sroffset: 1,
continue: "-||",
},
query: {
searchinfo: {
totalhits: 12
},
search: [
{
ns: 0,
title: "그랜드 테프트 오토 V",
pageid: 797633,
}
],
},
}
I want to get title value.
I try
testToJson.get("title")
but it returns null.
How to get title value with jackson?
You can deserialise it to a JsonNode and use JSON Pointer to get required field:
JsonNode node = mapper.readValue(jsonFile, JsonNode.class);
String title = node.at("/query/search/0/title").asText();
you could build a class for this json result then read from it.
public class Result {
private JsonNode searchinfo;
private JsonNode[] searches;
}
// then read:
Result testToJson = objectMapper.readValue(test, Result.class);
System.out.println(testToJson.getSearches(0).get("title"));
refer
It is impossible to read JSON into an instance of a generic class like that because the info about generics are used in compile time and already lost when program is running.
Jackson captures the data about generics using a sub-classed instance of TypeReference<T>.
Map<String, String> testToJson = objectMapper.readValue(test, new TypeReference<Map<String, String>>(){});
The problem with this approach is that Map<String, String> almost never describes complex data (like in the example) correctly. The example contains not only string values, there are numbers and even nested objects.
In situations like that, when you don't want or cannot write a class that describes the structure of the JSON, the better choice is parsing the JSON into a tree structure and traverse it. For example:
JsonNode node = objectMapper.readTree(test);
String title = node.get("query").get("search").get(0).get("title").asText();
Integer offset = node.get("continue").get("strOffset").asInt()

How to handle both a single item and array of item for same property in springboot [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.

Gson fromJson deserialize

I have the following json:
[
{
"": "",
"substituted_restday": "2020-02-01",
"original_restday": "2020-02-08",
"id": "15d13f70-c0a852c0-3a925f13-6dca1982",
"_UNIQUEKEY_": "15d1592a-c0a852c0-3a925f13b7c65023",
"parentId": ""
},
{
"": "",
"substituted_restday": "2020-02-03",
"original_restday": "2020-02-09",
"id": "15d14d55-c0a852c0-3a925f13-727b70af",
"_UNIQUEKEY_": "15d1592a-c0a852c0-3a925f13-3711a584",
"parentId": ""
}
]
I want to get the value of "substituted_restday" and "original_restday" from the JSON. So I used gson.from with the following syntax to concert it into JAVA object.
String[] str = gson.fromJson(JSON, String[].class);
However, it showed the following error:
com.google.gson.JsonParseException: The JsonDeserializer StringTypeAdapter failed to deserialize json object {"":"","substituted_restday":"2020-02-01","original_restday":"2020-02-08","id":"15d13f70-c0a852c0-3a925f13-6dca1982","_UNIQUEKEY_":"15d1592a-c0a852c0-3a925f13-b7c65023","parentId":""} given the type class java.lang.String
So, how can I get the value of "substituted_restday" and "original_restday" from the JSON? Thank you?
Tree Structure
Gson can parse the JSON into a tree structure, similar to how XML can be parsed into a DOM tree. The nodes of the tree can be one of these subclasses of JsonElement: JsonObject, JsonArray, JsonPrimitive, and JsonNull.
Since the JSON starts with a [, you can parse into a JsonArray, like this:
JsonArray root = gson.fromJson(JSON, JsonArray.class);
for (JsonElement elem : root) {
JsonObject obj = elem.getAsJsonObject();
String substituted_restday = obj.get("substituted_restday").getAsString();
String original_restday = obj.get("original_restday").getAsString();
System.out.printf("substituted_restday = '%s', original_restday = '%s'%n",
substituted_restday, original_restday);
}
List of Maps
Gson can parse the JSON objects into a Map.
List<Map<String, String>> root = gson.fromJson(JSON, new TypeToken<List<Map<String, String>>>() {}.getType());
for (Map<String, String> obj : root) {
String substituted_restday = obj.get("substituted_restday");
String original_restday = obj.get("original_restday");
System.out.printf("substituted_restday = '%s', original_restday = '%s'%n",
substituted_restday, original_restday);
}
Array of POJOs
Gson can parse the JSON objects into POJOs. This is the most type-safe way to handle the data.
MyObj[] root = gson.fromJson(JSON, MyObj[].class);
for (MyObj obj : root) {
System.out.printf("substituted_restday = '%s', original_restday = '%s'%n",
obj.substitutedRestday, obj.originalRestday);
}
class MyObj {
#SerializedName("")
String blank;
#SerializedName("substituted_restday")
String substitutedRestday;
#SerializedName("original_restday")
String originalRestday;
#SerializedName("id")
String id;
#SerializedName("_UNIQUEKEY_")
String uniqueKey;
#SerializedName("parentId")
String parentId;
}
You would likely want getter and setter methods on your POJO. This is just a simplified running example.
Output (from all 3)
substituted_restday = '2020-02-01', original_restday = '2020-02-08'
substituted_restday = '2020-02-03', original_restday = '2020-02-09'
JsonObject jsonObject = gson.fromJson( JSON, JsonObject.class);
then
jsonObject.get(substituted_restday); // returns a JsonElement for that name
jsonObject.get(original_restday);
Imo, you should create a pojo for the json element and then have fromJson method return an array of that pojo's. This link should give you more details - https://howtodoinjava.com/gson/gson-parse-json-array/

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.

Remove element.field from ArrayNode

I have such json ArrayNode and I need to remove from each element for example field "xxx" using ObjectMapper, ArrayNode, JsonNode or ObjectNode. But without Gson and #JsonIgnore etc.
"arrayNode": [
{
"xxx": {},
"yyy": {}
},
{
"xxx": {},
"yyy": {}
}
]
I am not sure whether this problem has been solved or not. But following code snippet shows how to remove a field whose key is xxx from JSON node. And a JsonNode cannot perform insertion or deletion, so you have to cast it to ObjectNode for further manipulation.
Code snippet
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonStr);
rootNode.get("arrayNode").forEach(e -> {
if (e.has("xxx")) {
ObjectNode objNode = (ObjectNode) e;
objNode.remove("xxx");
}
});
System.out.println(rootNode.toString());
Console output
{"arrayNode":[{"yyy":{}},{"yyy":{}}]}
You can use this maven dependency : http://mvnrepository.com/artifact/org.json/json/20160212
It's very simple to understated and use. ex:
JSONObject obj = "YOUR_JSON_STRING";
JSONArray result = obj.getJSONArray("YOUR_STRING_KEY");
for(JSONObject elem : result){
String out = elem.getString("xxx");
}
More you can read at : https://developer.android.com/reference/org/json/JSONArray.html
Good luck

Categories