Java Jackson wrap an existing json with a root entry - java

I'm a new user of fasterxml.jackson lib. I need an help to undestand how use that lib.
I have an array generated from a string, that I need to include into a root node, but I didn't understand how do that.
My code is:
class RigaAnamnesi {
int codRiga;
String testo;
boolean domandaSiNo;
Integer sub = 0;
String spiegazione = "Spiegazione di prova";
}
ArrayList<RigaAnamnesi> vArray = fillArray();
String json = mapper.writeValueAsString(vArray);
JsonNode parsedJson = mapper.readTree(json);
ArrayNode outerArray = mapper.createArrayNode();
ObjectNode outerObject = mapper.createObjectNode();
outerObject.putPOJO("domande", parsedJson);
outerArray.add(outerObject);
File f = Paths.get("anamnesi.json").toFile();
mapper.writeValue(f, outerArray);
and my output is:
{
"domande": [
{
"codRiga": 1,
"testo": "Malattie del sangue e problemi di coagulazione_",
"domandaSiNo": true,
"sub": 0,
"spiegazione": "Spiegazione di prova"
},
{
"codRiga": 2,
"testo": "Malattie endocrine (es.Diabete, Osteoporosi)___ ",
"domandaSiNo": true,
"sub": 0,
"spiegazione": "Spiegazione di prova"
},
{
"codRiga": 3,
"testo": "Malattie cardiache e vascolari_",
"domandaSiNo": true,
"sub": 0,
"spiegazione": "Spiegazione di prova,"
},
...
but I need to include into a new root:
{
"anamnesi": {
"domande": [
{
"codRiga": 1,
"testo": "Malattie del sangue e problemi di coagulazione_",
"domandaSiNo": true,
"sub": 0,
"spiegazione": ""
},
....

The Jackson ObjectNode represents a JSON object {}. To add properties, you can either call set(String, JsonNode) which adds another node (object, array, or simple value) or you can call putPOJO(String, Object). POJO stands for Plain Old Java Object and this call will interpret your List<RigaAnamnesi> class as an array of JSON objects.
To get to your desired structure, you do not need to print the array to a string first. Instead, you can create two objects and use putPOJO followed by set:
List<RigaAnamnesi> vArray = ...;
ObjectNode domande = mapper.createObjectNode();
// use putPOJO to make sure jackson converts the POJO to JsonNodes
domande.putPOJO("domande", vArray);
// this is the parent we will print
ObjectNode anamnesi = mapper.createObjectNode();
// use set, since domande already is a JsonNode
anamnesi.set("anamnesi", domande);
System.out.println(mapper.writeValueAsString(anamnesi));

Related

Set child node as root node using jackson

The question is quite simple:
From this:
{
"categoryId":"some_id",
"properties": {
"id": "braja_de_nana",
"displayName": "test",
"longDescription": "<p>TESTE</p>",
"active": true,
"attributes": [
{
"name": "made",
"value": "THIS_BECOMES_A_NODE_VALUE",
"property": "THIS_BECOMES_A_NODE_NAME"
},
{
"name": "made",
"value": "THIS_BECOMES_A_NODE_VALUE_2",
"property": "THIS_BECOMES_A_NODE_NAME_2"
}
]
}
}
UPDATE
This should be the result:
It means that every array element of 'attributes' should become a new root node.
set 'property' from 'attributes' as the object node name.
set 'value' from 'attributes' as the object node value.
{
"categoryId":"some_id",
"THIS_BECOMES_A_NODE_VALUE":"THIS_BECOMES_A_NODE_NAME",
"THIS_BECOMES_A_NODE_NAME_2":"THIS_BECOMES_A_NODE_VALUE_2"
"properties": {
"id": "braja_de_nana",
"displayName": "test",
"longDescription": "<p>TESTE</p>",
"active": true
}
}
This is a challenge for me.
I can set new nodes into the root node.
Already got a map from 'attributes' and then tried to iterate them with forEach in order to put the result into one single node, but instead as shown I have to take the 'property' set it to the object name´s key, then get the value and set to its value.
UPDATE 2
#Override
public String toOccProductDTO(ProcessProductDTO processProductDTO) throws JsonProcessingException {
OccProductDTO occProductDTO = OccProductDTO.builder()
.categoryId(processProductDTO.getCategoryId())
.productType(processProductDTO.getCategoryId())
.properties(toOccProductPropertiesDTO(processProductDTO))
.build();
toOccProductPropertiesDTO(processProductDTO);
String tree = mapper.writeValueAsString(occProductDTO);
JsonNode root = mapper.readTree(tree);
JsonNode attributesNodeArray = ((ObjectNode) root.get("properties"))
.remove("p_specs");
Iterator<JsonNode> arrayNodes = attributesNodeArray.iterator();
while (arrayNodes.hasNext()) {
JsonNode node = arrayNodes.next();
root = ((ObjectNode)root).set(node.get("value").asText(), node.get("property"));
}
System.out.println(root.toPrettyString());
return null;
}
I got an: arrayNodes: Collection$EmptyIterator at that line.
Am I doing something wrong?
If you are trying to the attributes to the root node, you can remove that node and add its fields to the root.
The "attributes" node is an array with length 1, so you have to get the first element of the array to get the attribute fields.
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);
JsonNode attributesNodeArray = ((ObjectNode) root.get("properties"))
.remove("attributes");
JsonNode attributesNode = attributesNodeArray.get(0);
Iterator<String> fieldNames = attributesNode.fieldNames();
while (fieldNames.hasNext()) {
String name = fieldNames.next();
root = ((ObjectNode)root).set(name, attributesNode.get(name));
}
System.out.println(root.toPrettyString());
Output:
{
"categoryId" : "some_id",
"properties" : {
"id" : "braja_de_nana",
"displayName" : "test",
"longDescription" : "<p>TESTE</p>",
"active" : true
},
"name" : "made",
"value" : "some value",
"property" : "some_value"
}
UPDATE
For the updated question, you can do the following:
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);
JsonNode attributesNodeArray = ((ObjectNode) root.get("properties"))
.remove("attributes");
Iterator<JsonNode> arrayNodes = attributesNodeArray.iterator();
while (arrayNodes.hasNext()) {
JsonNode node = arrayNodes.next();
root = ((ObjectNode)root).set(node.get("value").asText(), node.get("property"));
}
System.out.println(root.toPrettyString());
Output:
{
"categoryId" : "some_id",
"properties" : {
"id" : "braja_de_nana",
"displayName" : "test",
"longDescription" : "<p>TESTE</p>",
"active" : true
},
"THIS_BECOMES_A_NODE_VALUE" : "THIS_BECOMES_A_NODE_NAME",
"THIS_BECOMES_A_NODE_VALUE_2" : "THIS_BECOMES_A_NODE_NAME_2"
}
Maybe it was more complex than expected.
It turns out that I solved the problem with Oboe´s help. Although he missed some points through his implementation plus some changes I could achieve the goal.
//Converts the parsed objects into Json String
String tree = mapper.writeValueAsString(occProductDTO);
//Reads the json string to JsonNode in order to manipulate it
JsonNode root = mapper.readTree(tree);
//Sets the chosen node where the new nodes should be created
JsonNode properties = root.path("properties");
//maps the two attribs needed
Map<String, String> attribs = processProductDTO.getProductDTO().getAttributes().stream()
.collect(Collectors.toMap(AttributeDTO::getProperty, AttributeDTO::getValue));
//Converts each attrib into a String list
List<String> props = attribs.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry<String, String>::getValue).reversed())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
List<String> names = attribs.entrySet()
.stream() .sorted(Comparator.comparing(Map.Entry<String,String>::getValue).reversed())
.map(Map.Entry::getValue)
.collect(Collectors.toList());
//iterates over the two lists adding the attribs to their corresponding position
Iterator<String> arrayNodes = props.listIterator();
Iterator<String> arrayNodes2 = names.listIterator();
while (arrayNodes.hasNext()) {
String node = arrayNodes.next();
String node2 = arrayNodes2.next();
properties = ((ObjectNode)properties).put(node, node2);
}
return mapper.writeValueAsString(root);
}
In the end, instead of passing a java object via #Post, I´m passing a json String by using "consumes = application/json, produces = "application.json"
That´s it!
Maybe it could be achieved and better implemented with java 8 stream, but for now it works.
Suggestion to improve the code are welcome!

Stringify all values in a newline delimited JSON by keys

I have a newline delimited JSON and I wish to change values of type map to strings using Java. An example is:
{"id": 1, "data": {}}
{"id": 1, "data": {"time": 43}}
{"id": 1, "data": {"class" : {"students" : [{"name" : "Jane"}]}}}
should be changed to
{"id": 1, "data": "{}"}
{"id": 1, "data": "{\"time\": 43}"}
{"id": 1, "data": "{\"class\" : {\"students\" : [{\"name\" : \"Jane\"}]}}"}
I wish to stringify all the data map values. How can I do this?
This is a problem that calls for a JSON processor, since this will provide for the most bullet-proof, simple solutions. Java doesn't come with built-in JSON processing, so this will require a third party library. One commonly used Java JSON library is Jackson.
Since this particular request involves working with arbitrary data formats, the Jackson Tree Model in the Jackson Databind library is a good fit.
String delimitedJson = "{\"id\": 1, \"data\": {}}\n"
+ "{\"id\": 1, \"data\": {\"time\": 43}}\n"
+ "{\"id\": 1, \"data\": {\"class\" : {\"students\" : [{\"name\" : \"Jane\"}]}}}";
StringBuilder output = new StringBuilder();
JsonMapper jsonMapper = JsonMapper.builder().build();
MappingIterator<ObjectNode> i =
jsonMapper.readerFor(ObjectNode.class).readValues(delimitedJson);
i.forEachRemaining((ObjectNode jsonNode) ->
output.append(convertObjectsToString(jsonMapper, jsonNode).toString())
.append("\n"));
System.out.println(output);
// ...
private ObjectNode convertObjectsToString(JsonMapper jsonMapper,
ObjectNode jsonNode) {
ObjectNode copy = jsonMapper.createObjectNode();
jsonNode.fields().forEachRemaining(e -> {
if (e.getValue() instanceof ObjectNode) {
copy.set(e.getKey(), new TextNode(e.getValue().toString()));
} else {
copy.set(e.getKey(), e.getValue());
}
});
return copy;
}
Explanation
The ObjectMapper class is the primary class in the Jackson Databind library, and JsonMapper is the JSON-format specific implementation.
After creating the instance (using JsonMapper.builder().build()), we iterate over each element of the newline-delimited list using ObjectReader.readValues(delimitedJson), which reads a number of whitespace separated JSON values from an input source. In this example, I'm assuming the root level JSON values in your list are objects, and not e.g. strings or ints.
MappingIterator<ObjectNode> i =
jsonMapper.readerFor(ObjectNode.class).readValues(delimitedJson);
i.forEachRemaining((ObjectNode jsonNode) ->
output.append(convertObjectsToString(jsonMapper, jsonNode).toString())
.append("\n"));
The custom convertObjectsToString method returns an ObjectNode, which is converted to JSON using toString().
The convertObjectsToString method starts by creating a new empty ObjectNode. For each property in the source node, if it's not a JSON object type, it is copied over directly. If it is a JSON object, it is converted to the JSON string representation of the object.
private ObjectNode convertObjectsToString(JsonMapper jsonMapper,
ObjectNode jsonNode) {
ObjectNode copy = jsonMapper.createObjectNode();
jsonNode.fields().forEachRemaining(e -> {
if (e.getValue() instanceof ObjectNode) {
copy.set(e.getKey(), new TextNode(e.getValue().toString()));
} else {
copy.set(e.getKey(), e.getValue());
}
});
return copy;
}

add object to existing JSON file JAVA

I'm trying to add a new JSON object inside cars.json in "carTypes"
How would I go about doing this?
Im able to fetch data from cars.json but don't know how to add data to it
My current cars.json file
"carTypes": [
{
"model": "toyota",
"make": "corolla",
"year": "2005"
}
],
How I want it to be
"carTypes": [
{
"model": "toyota",
"make": "corolla",
"year": "2005"
},
{
"model": "civic",
"make": "honda",
"year": "2017"
}
],
Assuming you have an ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
and you already have the content of your first snippet inside a JsonNode that you loaded from somewhere,
JsonNode carTypes = mapper.readTree(...);
then you should:
ArrayNode array = (ArrayNode) jsonNode.get("carTypes"); //<-- 1) convert the node into ArrayNode
ObjectNode objNode = mapper.createObjectNode(); //<-- 2) create a new object node
objNode.put("model", "civic"); //<-- add your attributes to the new object node
array.put(objNode); //<-- put the new node inside the array
Then you can convert your array back to JsonNode and do whatever you want with your Json.
If you use org.json and have loaded the JSON:
JSONObject obj = new JSONObject(jsonStr);
Then you can get to the "carTypes" array and add the new element:
JSONArray arr = obj.getJSONArray("carTypes");
JSONObject hondaCivic17Json = new JSONObject()
.put("model", "civic")
.put("make", "honda")
.put("year", "2017");
JSONArray newArray = arr.put(hondaCivic17Json);
JSONObject newJson = obj.put("carTypes", newArray);
String newJsonStr = newJson.toString();
System.out.println(newJsonStr);
Output:
{
...
"carTypes":
[
{"year":"2005","model":"toyota","make":"corolla"},
{"year":"2017","model":"civic","make":"honda"}
]
...
}
You can override the file like this:
Files.write(path, newJson.toString().getBytes());

How to replace json node in jsonNode or ObjectNode

I have a JSON node-like below. The structure of JsonNode will change dynamically.
Now I want to replace/update the value of a particular key.
Sample JSON One
{
"company": "xyz",
"employee": {
"name": "abc",
"address": {
"zipcode": "021566"
}
}
}
Sample JSON Two
{
"name": "abc",
"address": {
"zipcode": "021566"
}
}
I want to replace the zip code value 021566 to 566258. I know key name (zipcode), old and new zip code value but I don't know the path of zip code. I tried multiple ways using com.fasterxml.jackson.databind.JsonNode - put, replace
Is there any way to update in java?
JsonNodes are immutable, but you can find the value you want from a JsonNode, cast the original to an ObjectNode, replace the value, then cast that back to a JsonNode. It's a little odd, I know, but it worked for me.
public static void findAndReplaceJsonNode throws JsonProcessingException {
String jsonOne = "{ \"company\" : \"xyz\", \"address\" : { \"zipcode\" : \"021566\", \"state\" : \"FL\" } }";
String jsonTwo = "{ \"company\" : \"abc\", \"address\" : { \"zipcode\" : \"566258\", \"state\" : \"FL\" } }";
ObjectMapper mapper = new ObjectMapper();
JsonNode nodeOne = mapper.readTree(jsonOne);
JsonNode nodeTwo = mapper.readTree(jsonTwo);
JsonNode findNode = nodeTwo.get("address");
ObjectNode objNode = (ObjectNode) nodeOne;
objNode.replace("address", findNode);
nodeOne = (JsonNode) objNode;
System.out.println(nodeOne);
}
Output:
{"company":"xyz","address":{"zipcode":"566258","state":"FL"}}
Disclaimer: While I do some JSON parsing and processing on a regular basis, I certainly wouldn't say that I'm adept at it or tree traversals with them. There is more than likely a better way to find the value of a child in a JsonNode than by taking the entire child as a node, replacing it's one value and then replacing the node. This should work for you in a pinch, though :)

How to get count all json nodes using Jackson framework

Here is my user.json
{
"id":1,
"name":{
"first":"Yong",
"last":"Mook Kim"
},
"contact":[
{
"type":"phone/home",
"ref":"111-111-1234"
},
{
"type":"phone/work",
"ref":"222-222-2222"
}
]
},
{
"id":2,
"name":{
"first":"minu",
"last":"Zi Lap"
},
"contact":[
{
"type":"phone/home",
"ref":"333-333-1234"
},
{
"type":"phone/work",
"ref":"444-444-4444"
}
]
}
I would like count how many json object is in there. For example the above json has 2 json object id = 1 and id =2.
//tree model approach
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(new File("user.json"));
List<JsonNode> listOfNodes = rootNode.findParents("first");
System.out.println(listOfNodes.size());
Giving me size = 1.
Can you please tell me what i am doing wrong?
Thanks
Your java code is correct but your json file is invalid.
Jackson parses only first valid element ("Yong").
To fix this just add [ at the begining and ] at the end of file (make it array).

Categories