I have a new JsonNode that I created
JsonNode jNode = new ObjectCodec().createObjectNode();
with this node, how do I then add key value pairs within so that I can construct this new node with the new values? What I read in http://www.cowtowncoder.com/blog/archives/2011/08/entry_460.html mentioned about using
jNode.with("newNode").put("key1","value1");
But looking at the APIs for Jackson's JsonNode (v1.8) does not show any method as such.
These methods are in ObjectNode: the division is such that most read operations are included in JsonNode, but mutations in ObjectNode and ArrayNode.
Note that you can just change first line to be:
ObjectNode jNode = mapper.createObjectNode();
// version ObjectMapper has should return ObjectNode type
or
ObjectNode jNode = (ObjectNode) objectCodec.createObjectNode();
// ObjectCodec is in core part, must be of type JsonNode so need cast
I've recently found even more interesting way to create any ValueNode or ContainerNode (Jackson v2.3).
ObjectNode node = JsonNodeFactory.instance.objectNode();
Related
I have following class that is POJO of JSON document:
public class ApiResponse {
private boolean success;
private List<ApiRecord> data;
}
I deserialize object using ObjectMapper class in the following way:
var apiResponse = mapper.readValue(target, ApiResponse.class);
I want to make Jackson treat every ApiRecord deserialization failure as not failure of whole deserialization process but instead just get a list that contains only valid parsed objects, so the wrong elements of 'data' field are acceptable (not appearing in POJO list) and not blocking the rest ones.
Any idea on how to do this?
Do one thing add one property to the mapper object.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
var apiResponse = mapper.readValue(target, ApiResponse.class);
My solution to this problem was to write my own deserializer which in case of failure returns null for array's element and tag the field that needs to use this deserializer with #com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = SomeClass.class).
How to generate an empty json node using jackson-java. I tried with NullNode.instance, but that returns
"totals":null
Whereas I want totals to be an empty instance.
{
"totals": {},
"orderId": "550047004",
"numberOfItems": 2
}
You should use ObjectNode. It can be created with ObjectMapper:
ObjectNode node = mapper.createObjectNode();
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);
....}
Here is an example json
{
"key1": {
"key2": {
"key3": "value3"
}
}
}
I want to get the value of key3, which is "value3"
The method findValue of JsonNode class should serve the purpose here.
so I tried the following:
final ObjectMapper jsonMapper = new ObjectMapper();
String jsonRoot = "{\"key1\":\n" + " {\"key2\":\n" + " {\"key3\":\"value3\"}\n" + " }\n" + "}";
JsonNode node = jsonMapper.convertValue(jsonRoot,JsonNode.class);
JsonNode found = node.findValue("key3");
System.out.println(found.asText());
System.out.println(found.isObject());
However, I see "found" is null.
I am unable to figure out why this failing. I also tried node.findValue("key2"). I still get null.
Thanks
There is difference in between these 2 methods
JsonNode.get() method returns null
Use JsonNode.path(String).asText() which checks if node is present or
not, if not then it returns empty string.
The convertValue function is used to convert one instance type into another instance type. It is a two step conversion process which is equivalent to first serializing given value into JSON, then binding JSON data into value of second given type.
In your example above, the first argument of convertValue is actually a JSON(represented in a string) and not an object, hence this does not work.
To make this work, you can use following methods :
Method 1 :
JsonNode node = jsonMapper.readTree(jsonRoot);
This will deserialize the json as a tree and returns the root of the tree which can be used for traversal now.
Method 2 :
JsonNode node = jsonMapper.readValue(jsonRoot, JsonNode.class);
This will deserialize the json to JsonNode object directly.
So something like this should work.(although untested)
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(new File("c:\\example.json"));
JsonNode key1Node = root.path("key1");
JsonNode key2Node = key1Node.path("key2");
access value of key 3 node
String val = key2Node.path("key3").asText();
See Reference here.
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