I m using jackson library to deserialize from Json. I need to extract only 2 value from this json i.e. c1 and d1. I have used this code... I need to know the correct approach to overcome get c1 and d1 values...
My json
{"Alpha":{"A":{"B":{"C":{"c1":1234,c2:"abcd"},"D":{"d1":"xyz","d2":5678,"d3":"qwerty"},"E":[{"e1":456,"e2":"mnop"},{"e1":098,"e2":"qrst"}]}}},"X"{"x1":8098}}
ObjectMapper mapper = new ObjectMapper();
mainclass alphaobj = mapper.readValue(new File("C:\\employee.json"), mainclass.class);
System.out.println(alphaobj.A.B.C.getc1());
Maybe you should use Jackson Tree Model instead?
Something like:
JsonNode root = mapper.readTree(file);
int c1 = root.path("Alpha").path("A").path("C").path("C1").intValue();
and so on.
Related
Objective: deep copy (or clone) of a Java object
One of the suggested ways (almost everywhere) to do it is using Jackson:
MyPojo myPojo = new MyPojo();
ObjectMapper mapper = new ObjectMapper();
MyPojo newPojo = mapper.readValue(mapper.writeValueAsString(myPojo), MyPojo.class);
Question: is the following better? in terms of performance? is there any drawbacks?
MyPojo myPojo = new MyPojo();
ObjectMapper mapper = new ObjectMapper();
MyPojo newPojo = mapper.treeToValue(mapper.valueToTree(myPojo), MyPojo.class);
Answered by Tatu Saloranta:
Second way should be bit more efficient since it only creates and uses
logical token stream but does not have to encode JSON and then decode (parse) it to/from token stream. So that is close to optimal regarding
Jackson.
About the only thing to make it even more optimal would be to directly
use TokenBuffer (which is what Jackson itself uses for buffering). Something like:
TokenBuffer tb = new TokenBuffer(); // or one of factory methods
mapper.writeValue(tb, myPojo);
MyPojo copy = mapper.readValue(tb.asParser(), MyPojo.class);
This would further eliminate construction and traversal of the tree model. I don't know how big a difference it'll make, but is not much more code.
Thanks Tatu :)
I have copied my "valueNode" during iteration and made a copy of it using ObjectMapper now "copyJsonNode" is the replica of "valueNode" which i need for further implementation.
if (entry.getKey().equalsIgnoreCase("admin")) {
JsonNode valueNode = entry.getValue();
String copyjson = valueNode.toString();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode copyJsonNode = objectMapper.readTree(copyjson);
....}
I have a Java object Results:
public class MetaData {
private List<AttributeValue<String,Object>> properties
private String name
...
... getters/setters ...
}
The AttributeValue class is a generic key-value class. It's possible different AttributeValue's are nested. The (value) Object will then be another AttributeValue and so forth.
Due to legacy reasons the structure of this object cannot be altered.
I have my JSON, which I try to map to this object.
All goes well for the regular properties. Also the first level of the list is filled with AttributeValues.
The problem is the Object. Jackson doesn't know how to interpret this nested behavior and just makes it a LinkedHashMap.
I'm looking for a way to implement custom behavior to tell Jackson this has to be a AttributeValue-object instead of the LinkedHashMap.
This is how I'm currently converting the JSON:
ObjectMapper om = new ObjectMapper();
MetaData metaData = om.readValue(jsonString, new TypeReference<MetaData>(){});
And this is example JSON. (this is obtained by serializing an existing MetaData object to JSON, I have complete control over this syntax).
{
"properties":[
{
"attribute":"creators",
"value":[
{
"attribute":"creator",
"value":"user1"
},{
"attribute":"creator",
"value":"user2"
}
]
},{
"attribute":"type",
"value": "question"
}
],
"name":"example"
}
(btw: I've tried the same using GSON, but then the object is a StringMap and the problem is the same. Solutions using GSON are also welcome).
edit In Using Jackson ObjectMapper with Generics to POJO instead of LinkedHashMap there is a comment from StaxMan:
"LinkedHashMap is only returned when type information is missing (or if Object.class is defined as type)."
The latter seems to be the issue here. Is there a way I can override this?
If you have control over the serialization, try calling enableDefaultTyping() on your mapper.
Consider this example:
Pair<Integer, Pair<Integer, Integer>> pair = new Pair<>(1, new Pair<>(1, 1));
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pair);
Pair result = mapper.readValue(str, Pair.class);
Without enableDefaultTyping(), I would have str = {"k":1,"v":{"k":1,"v":1}} which would deserialize to a Pair with LinkedHashMap.
But if I enableDefaultTyping() on mapper, then str = {"k":1,"v":["Pair",{"k":1,"v":1}]} which then perfectly deserializes to Pair<Integer, Pair<...>>.
I need to persist an attribute in DynamoDB Table, whhere attribute is Set<Some Class>.
Basically I need to put that attribute in Map<String,AttributeValue>.
For generation situation we generally do
Map<String,AttributeValue> itemsInTable = new HashMap<String, AttributeValue>();
itemsInTable.put("Id", new AttributeValue("123"));
Now suppose I have a Set<Info> where Info is a class.
How to put that kind of Attribuute?
and also if the attribute Value is a list ??
After two three days of research I just found there is no direct way to put something like set<Info> in DynamoDB using this kind of Notation.
Map<String,AttributeValue> itemsInTable = new HashMap<String, AttributeValue>();
itemsInTable.put("Id", new AttributeValue("123"));
But we can opt some middle way to convert the Object to JSONObject or JSONString and put in Map<String,AttributeValue> by using
Set<String> set = new HashSet<String>();
Map<String,AttributeValue> itemsInTable = new HashMap<String, AttributeValue>();
itemsInTable.put("Id", new AttributeValue().withSS(set));
To convert object to jsonString we can take help of jackson library.
import this:
import zaaa.org.codehaus.jackson.map.ObbjectMapper
Define ObjectMapper
private final ObjectMapper jacksonObjectMapper = new ObjectMapper();
Now suppose class is Container and its corresponding Object is `container'
Now the main job is to convert it into jsonString which can be easily done by using writevalueAsString function.
String jsonString = jacksonObjectMapper.writeValueAsString(container)
Now we have jsonString, we can easily convert it to JSONObject or JSONArray whenever needed.
I solved my issue by using this way.
I have a org.json.JSONArray that contains JSONObjects and I am trying to map those to a POJO. I know the type of the POJO I want to map to. I have 2 options and I m trying to figure out which is better in performance.
Option 1:
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader().withType(MyPojo.class);
for (int i = 0; i < jsonArr.length(); i++) {
JSONObject obj = jsonArr.getJSONObject(i);
MyPojo pojo = reader.readValue(obj.toString());
... other code dealing with pojo...
}
Option 2:
ObjectReader mapper = new ObjectMapper();
for (int i = 0; i < jsonArr.length(); i++) {
JSONObject obj = jsonArr.getJSONObject(i);
MyPojo pojo = mapper.convertvalue(obj, MyPojo.class);
... other code dealing with pojo...
}
For sake of argument, lets assume the length of the JSONArray is 100.
From what I have looked so far from the source code, option 1 seems better since the Deserialization context and the Deserializer is created only once, while in case of option 2, it will be done for each call.
Thoughts?
Thanks!
I will try to explain the difference, with the problem I faced. I used both in a complex conversion I needed to use.
My request was of the format as below.
"{Key=a1, type=ABC}"
I wanted to convert it to some class's (A1) instance.
class A1 {
private String key;
private String type;
}
As is clear, the keys are not strings (i.e. not enclosed in double quotes)
With mapper.readValue
I will get error as below:
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('k' (code 115)): was expecting double-quote to start field name
With mapper.convertValue
I will get an instance of A1 as I required.
I'm just starting using the Jackson JSON library. Jackson is a very powerful library, but it has a terribly extensive API. A lot of things can be done in multiple ways. This makes it hard to find your way in Jackson - how to know what is the correct/best way of doing things?
Why would I use this solution:
String json = "{\"a\":2, \"b\":\"a string\", \"c\": [6.7, 6, 5.6, 8.0]}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readValue(json, JsonNode.class);
if (node.isObject()) {
ObjectNode obj = mapper.convertValue(node, ObjectNode.class);
if (obj.has("a")) {
System.out.println("a=" + obj.get("a").asDouble());
}
}
Over a solution like this:
String json = "{\"a\":2, \"b\":\"a string\", \"c\": [6.7, 6, 5.6, 8.0]}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
if (node.isObject()) {
ObjectNode obj = (ObjectNode) node;
if (obj.has("a")) {
System.out.println("a=" + obj.get("a").asDouble());
}
}
Or over solutions that I came across using JsonFactory and JsonParser and maybe even more options...
It seems to mee that mapper.readValue is most generic and can be used in a lot of cases: read to JsonNode, ObjectNode, ArrayNode, PoJo, etc. So why would I want to use mapper.readTree?
And what is the best way to convert a JsonNode to an ObjectNode? Just cast to ObjectNode? Or use something like mapper.convertValue?
readValue() can be used for any and all types, including JsonNode. readTree() only works for JsonNode (tree model); and is added for convenience.
Note that you NEVER want to use your first example: it is equivalent to writing out your node as JSON, then reading it back -- just cast it.
Read value can be used for your own java classes:
public class Foo {
private int a;
private String b;
private double[] c;
// getters/setters
}
String json = "{\"a\":2, \"b\":\"a string\", \"c\": [6.7, 6, 5.6, 8.0]}";
ObjectMapper mapper = new ObjectMapper();
Foo foo = mapper.readValue(json, Foo.class);
i.e. You may choose readTree when you do not know exact type of the Object, and readValue when you know the Object type for sure.
These methods have different runtime when you parsing same JSON
The fastest way is using readValue() with type reference HashMap:
TypeReference<HashMap<String, Object>> typeRef= new TypeReference<>() {};
HashMap<String, Object> parsedJson = objectMapper.readValue(json,typeRef);
Using readTree() and writing manual parser with JsonNode objects also wiil give you fast runtime.
Additional benefit of using readTree(): you can use stream parallel when parsing ArrayNode objects, which will boost runtime on multicore processors.
The slowest way is using readValue() with POJO class:
YourPOJO parsedJson = objectMapper.readValue(json, YourPOJO.class);
This is approximate runtime of each parsing way on same JSON:
Auto parsing raw map with ObjectMapper readValue() runtime: 34 ms
Auto parsing type reference map with ObjectMapper readValue() runtime: 6 ms
Auto parsing POJO with ObjectMapper readValue() runtime: 51 ms
Manual sequential parsing with ObjectMapper readTree() runtime: 18 ms
Manual stream parallel parsing with ObjectMapper readTree() runtime: 10 ms
I have done my example and tests here:
https://github.com/EvgenyUmansky/java-json-xml-processing/blob/master/src/test/java/JacksonTest.java
Another tests here:
https://gist.github.com/varren/3b7468a1d7abadad4958fe6bd7d42d44