How to convert JsonNode to ObjectNode - java

I have a com.fasterxml JsonNode object with some data. I need to do some manipulation on its data. I googled for answer but didn't got it properly. Can you please suggest me how to manipulate JsonNode data.
I have also tried to convert JsonNode to ObjectNode as follows
ObjectNode objectNode = (ObjectNode)filterJson;
but its giving following exception....
java.lang.ClassCastException: com.fasterxml.jackson.databind.node.TextNode cannot be cast to
com.fasterxml.jackson.databind.node.ObjectNode
please help!!

You can convert a JsonNode in an ObjectNode in this simple way:
ObjectNode objectNode = jsonNode.deepCopy();
Available from Jackson 2.0 and tested with Jackson 2.4.0

Finally, I got the solution as follows...
JsonNode jsonNode = Json.toJson("Json String");
ObjectNode node = (ObjectNode) new ObjectMapper().readTree(jsonNode.asText());
//perform operations on node
jsonNode = (JsonNode) new ObjectMapper().readTree(node.toString());
or another one as below...
ObjectNode node = (ObjectNode) new ObjectMapper().readTree("Json String")
//perform operations on node
jsonNode = (JsonNode) new ObjectMapper().readTree(node.toString());
but I don't know if this is good approach or not ?
If there is any better than above, please let me know.
Thank you!

I had this error too although in my case it was a stupid mistake.
I accidentally imported org.codehaus.jackson.node.ObjectNode instead of com.fasterxml.jackson.databind.node.ObjectNode.
Using the jackson ObjectNode fixed the issuse.

You can covert JsonNode to ObjectNode this way:
JsonNode demoPath = requestParams.at("/Subscription/0");
((ObjectNode) demoPath).put("mylID", "test12");

I try it some times, it will be ok! You only define a Student Class to map the properties. Then you could convert the jsonNode to Student Object.
Student student = objectMapper.convertValue(jsonNode1, Student.class);
I think this will be suitable for your need!

Related

How to access the value from a key-value pair in a jsonnode

I have got a JsonNode like the below
"{"Pink":["#000000"],"Red":["#000000"],"Blue":["#000000"],"Orange":["#000000"]}"
and I am trying to get the value for Pink for e.g like this
jsonNode.get("Pink").asText()
But this isn't working - is there another way that I can access these values through Java?
It looks like your problem here is that "Pink" is an array and not a string. The solution here is to either remove the square brackets, or if that is not possible, the following should give you the expected result:
jsonNode.get("Pink").get(0).asText()
This method will help you to traverse JsonNode
public void getColorCode() throws JsonProcessingException {
String color = "{\"Pink\":[\"#000000\"],\"Red\":[\"#000000\"],\"Blue\":[\"#000000\"],\"Orange\":[\"#000000\"]}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(color);
for (JsonNode colorCode : node.get("Pink")){
System.out.println(colorCode);
}
}

put ArrayNode inside ObjectNode

I would like to prepare an object as per below format. Array of objects inside an ObjectNode. I'm trying as per below.
{ [ {arrayNodeObject1}, {arrayNodeObject2}, {arrayNodeObject3} ] }
ArrayNode arrayNode = new ObjectMapper().createArrayNode();
arrayNode.add(arrayNodeObject1);
arrayNode.add(arrayNodeObject2);
arrayNode.add(arrayNodeObject3);
with the above code, I can able to get array of object as per below.
[{arrayNodeObject1}, {arrayNodeObject2}, {arrayNodeObject3}]
Now, I would like to put the above ArrayNode inside a ObjectNode. Please advise. Also, how can i read ArrayNode back from the ObjectNode.
If i can have a lable to the ArrayNode, it would be easy to get the arrayNode.
I think maps are the way to go here if you want to have labels:
Map arrayNodeObjectMap = new HashMap<String, ArrayNode>();
arrayNodeMap.put("labelForArrayNodeObject1", arrayNodeObject1);
arrayNodeMap.put("labelForArrayNodeObject2", arrayNodeObject2);
arrayNodeMap.put("labelForArrayNodeObject3", arrayNodeObject3);
This is how i did it using a stream:
ArrayNode arrayNode = mapper.createArrayNode();
arrayList.stream()
.forEach(id -> arrayNode.add(id));
objectNode.set("Key", arrayNode);
Or for your example:
ArrayNode arrayNode = new ObjectMapper().createArrayNode();
arrayNode.add(arrayNodeObject1);
arrayNode.add(arrayNodeObject2);
arrayNode.add(arrayNodeObject3);
objectNode.set("Key", arrayNode);
To retrieve this you can use:
objectNode.get("Key")
Note
set() has deprecated put() on ObjectNode to replace the use of put() where chaining with this is used. set() returns the node after adding/returning the property value

Selecting a subset of JSON properties and values using JSONPath

Given a JSON like:
{
"a":1,
"b":2,
"c":3,
"d":4,
"e":5
}
How can I select out b, d and e to get the following JSON?
{
"b":2,
"d":4,
"e":5
}
I want a JSON object and NOT only 2, 4 and 5 values?
This is what I'm trying with and failing:
$.[b,d,e]
JSONPath is not suitable for what you are trying to achieve: JSONPath is designed to select values and not key-value pairs. What you want could be achieved with Jackson or any JSON parser for Java.
If you want to go for Jackson here's the code that will do the trick:
String json = "{\"a\":1,\"b\":2,\"c\":3,\"d\":4,\"e\":5}";
ObjectMapper mapper = new ObjectMapper();
JsonNode tree = mapper.readTree(json);
ObjectNode node = mapper.createObjectNode();
node.set("b", tree.get("b"));
node.set("d", tree.get("d"));
node.set("e", tree.get("e"));
String result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
Elements must be in single quotes.
$.['b','d','e']
Works fine for JsonPath from com.jayway.jsonpath:json-path:2.4.0
Your json path is correct, while json it self is not. It should be:
{
"a":1,
"b":2,
"c":3,
"d":4,
"e":5
}
BTW there is good online testing resources for these purposes: http://jsonpath.com/
You need to modify your JSON to (as said by Andremoniy)
{
"a":1,
"b":2,
"c":3,
"d":4,
"e":5
}
and to select b,d,e use this
$.b,d,e

Unknown depth nested maps check key existence and get value

I have a hashmap of the following structure:-
mymap = {a:{b:{c:{d:{e}}}}
How do I check the existance of key "d" in hashmap mymap in the simplest way?
Is there any Java8 features that might come in handy here?
mymap.get( "a" )).get( "b" )..;
is not going to work because I don't know the level in which d is nested.
How do I check if d is present in the map, and get its value without this trailing call? Thanks in advance.
I have recently had a similar problem and managed to come up with a solution which works with any JSON depths.
It is a solution which transforms the String into a JsonNode Object and then tries to find the parent value of a given fieldName (in this case 'd'). The result returning something which is not null, will tell you if the value exists or not.
ObjectMapper mapper = new ObjectMapper();
String myMapJson = "{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":\"\"}}}}"
JsonNode data = mapper.readTree(myMapJson);
if (((ObjectNode)data.findParent("d")) != null) {
// Do something if value is found
} else {
// Do something if value is not found
}
Hope this helps..
You can use the FasterXML-Jackson library, which gives you the simplicty of traversing over nesed json.
For example:
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
String myMapJson = "{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":\"\"}}}}"
JsonNode data = mapper.readTree(myMapJson);
boolean hasKey = data.has("d");
Or, if you already have the object as Map you can write it as json and then load it the same way above:
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
String jsonData = mapper.writeValueAsString(myMapObject);
JsonNode data = mapper.readTree(jsonData);
boolean hasKey = data.has("d");
if (hasKey) {
JsonNode result = data.findValue("d");
}

Json manipulation on top of Jackson

Jackson is great for translating between POJO and json strings. But it's a pain to use it for manipulating a json string. I find myself doing stuff like:
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(ReadFile("testObj.json"));
((ObjectNode)node).put("testField", "newTestValue");
TestObject obj = mapper.readValue(mapper.writeValueAsString(node), TestObject.class);
And this is the simple example. It gets more complicated if you want to add a new object or an array of things. Is there a better way to do this?
I don't see what's so difficult. If you are certain your root JSON is a JSON object, simply cast the value returned by ObjectMapper#readTree(..) to an ObjectNode and manipulate it.
String json = "{\"sample\": \"some value\", \"nested\": {\"prop\": 123, \"nestedArray\":[1,2, \"string value\"], \"array\":[null, 42]}}";
ObjectNode node = (ObjectNode) new ObjectMapper().readTree(json);
System.out.println(node);
ArrayNode arrayNode = node.putArray("new array");
arrayNode.add(true).add(1).add("new value"); // chain add calls
arrayNode.addObject().put("nestedInArray", "nested object value"); // add an object and add to it
System.out.println(node);
prints
{"sample":"some value","nested":{"prop":123,"nestedArray":[1,2,"string value"],"array":[null,42]}}
{"sample":"some value","nested":{"prop":123,"nestedArray":[1,2,"string value"],"array":[null,42]},"new array":[true,1,"new value",{"nestedInArray":"nested object value"}]}
Note that you can also add your custom objects too. They will typically be wrapped in POJONode objects.

Categories

Resources