ObjectMapper readerForUpdating to replace array - java

I have two different JSON files.
File A:
{
"label": "A",
"links": [
{
"url": "urla"
}
]
}
File B:
{
"links": [
{
"url": "urlb"
}
]
}
Now I want to update A with the contents of B to get the following result JSON:
{
"label": "A",
"links": [
{
"url": "urlb"
}
]
}
That is the links array should be fully replaced with the contents of B.
But instead it merges the two Arrays:
{
"label": "A",
"links": [
{
"url": "urla",
"url": "urlb"
}
]
}
This is not desired.
The code for the merged file:
JsonNode A = ... // resolved from a service call
JsonNode B = ... // resolved from a service call
ObjectMapper mapper = new ObjectMapper();
result = mapper.readerForUpdating(A).readValue(B);
I also tried to set mapper.setDefaultMergeable(false); but it didn't help.
I use com.fasterxml.jackson.core:jackson-core:jar:2.9.8
Can someone help me?

Related

Is there a way to easily upade a JSON node using Jackson's ObjectMapper?

Given this JSON read from a file:
{
"Book": "Test",
"Subscription": [{
"RateIt": [{
"Id": "1234",
"Size": "XL",
"RateMe": [{
"id": "5678",
"Pages": ""
}],
"Test_Demo": null
}],
"DemoID": "test1111",
"subNumber": "9999"
}],
"Author_FirstName": "Test"
}
I tried to update DemoID field with a different value, this way:
ObjectMapper mapper = new ObjectMapper();
JsonNode requestParams = mapper.readTree(new File("src/test/resources/myFile.json"));
JsonNode subscriptionPath = requestParams.at("/Subscription");
System.out.println(subscriptionPath ); //value was retrieved OK
((ObjectNode) subscriptionPath).put("DemoID", "test0000"); //error on this line
But got the exception:
java.lang.ClassCastException: com.fasterxml.jackson.databind.node.TextNode cannot be cast to com.fasterxml.jackson.databind.node.ObjectNode
I also tried using the DemoIDpath instead, but got the same exception:
JsonNode idPath = requestParams.at("/Subscription/0/DemoID");//path was found OK
((ObjectNode) idPath).put("DemoID", "test0000"); // error on this line
What am I doing wrong with the use of ObjectNode?
Subscription is an array. You may see it better with proper formatting:
{
"Book": "Test",
"Subscription": [
{
"RateIt": [
{
"Id": "1234",
"Size": "XL",
"RateMe": [
{
"id": "5678",
"Pages": ""
}
],
"Test_Demo": null
}
],
"DemoID": "test1111",
"subNumber": "9999"
}
],
"Author_FirstName": "Test"
}
Change code to:
((ObjectNode) subscriptionPath.get(0)).put("DemoID", "test0000");

How to deep select Nodes based on given depth in Java?

I have json representation like below:
{
"total": "555",
"offset": "555",
"hasMore": "false",
"results": [
{
"associations": {
"workflowIds": [],
"companyIds": [],
"ownerIds": [],
"child": {
"name" : "association1",
"key" : "a1"
},
"quoteIds": [],
"contentIds": [],
"dealIds": [],
"contactIds": [
4646915
],
"ticketIds": []
},
"scheduledTasks": [
{
"taskType": "REMINDER",
"portalId": 214129,
"engagementType": "TASK",
"engagementId": 6604524566,
"timestamp": 1586815200000
}
]
},
{
"associations": {
"workflowIds": [],
"companyIds": [],
"ownerIds": [],
"quoteIds": [],
"contentIds": [],
"child": {
"name" : "association2",
"key" : "a2"
},
"dealIds": [],
"contactIds": [
4646915
],
"ticketIds": []
}
},
{
"associations": {
"workflowIds": [],
"companyIds": [],
"ownerIds": [],
"quoteIds": [],
"contentIds": [],
"dealIds": [],
"child": {
"name" : "association3",
"key" : "a3"
},
"contactIds": [
3995065
],
"ticketIds": []
}
},
{
"associations": {
"workflowIds": [],
"companyIds": [],
"ownerIds": [],
"quoteIds": [],
"contentIds": [],
"dealIds": [],
"contactIds": [
4648365
],
"ticketIds": []
}
}
]
}
I would like to get filtered information (something like sql) of given node by passing node selector string , to achieve this I am doing like below:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(new File("/Users/pra/automation/foo.json"));
String result = root.at("/results/0/associations/0/child").toString();
Assert.assertNotNull(result);
and this code is working as well, it filters first nodes out of array because 0 level index is passed, but I need output for all matching elements, so as to achieve that I passed * instead of 0 but it is not working.
means i am trying something like below ( which is failing ):
String result = root.at("/results/*/associations/*/child").toString();
Desired Output that needed:
[
{
"name" : "association1",
"key" : "a1"
},
{
"name" : "association2",
"key" : "a2"
},
{
"name" : "association3",
"key" : "a3"
}
]
I am open for other java based alternatives to achieve this. Thanks.
If you may switch to Gson library you may use im.wilk.vor:Voritem library gitHub or in Maven repository.
VorItem vorItemFactory = VorItemFactoryBuilder.standard.build();
JsonElement je = JsonParser.parse(...)
VorItem vi = vorItemFactory.from(je);
VorItem result = vorItemFactory.empty();
for (int idx = 0; idx < vi.get("result").list().size(); idx++) {
result.get(idx).set("name", vi.get("result").get(idx).get("associations/child/name");
result.get(idx).set("key", vi.get("result").get(idx).get("associations/child/key");
}
return result.asJsonElement().toString();
I found Andreas suggestion to be very effective and usage friendly, I was able to achieve desired output by using JSONPath library .
Usage code is as follows:
ObjectMapper objectMapper = new ObjectMapper();
String root = objectMapper.readTree(new File("/Users/pramo/automation/foo.json")).toString();
List<Object> associations = JsonPath.read(root, "$.results[*].associations.child");

Trying to get the name of the object whose collection array contains 'random'

I'm trying to get the names of the object whose collection array contains the word 'random'. Have tried various json path queries but couldn't get the right one.
{
"elements": [
{
"name": "My first element",
"language": "French",
"tags": ["Paris", "baguette", "Eiffel tower"]
},
{
"name": "randomOne",
"language": "Gibberish",
"tags": ["random", "plant, bag"]
},
{
"name": "bliep",
"language": "English",
"tags": ["lamp", "table, bed, oven"]
}
]}
Try this :
const jsonObj = {
"elements": [{
"name": "My first element",
"language": "French",
"tags": ["Paris", "baguette", "Eiffel tower"]
},
{
"name": "randomOne",
"language": "Gibberish",
"tags": ["random", "plant, bag"]
},
{
"name": "bliep",
"language": "English",
"tags": ["lamp", "table, bed, oven"]
}
]
};
let obj = jsonObj.elements.find((obj) => obj.tags.includes('random'));
console.log(obj.name); // randomOne
You can simply:
Loop through elements with Array.prototype.forEach()
Find instances containing "random" with Array.prototype.includes()
Add found names to result array with Array.prototype.push()
See below:
const jsondata = {
elements: [{
name: "My first element",
language: "French",
tags: ["Paris", "baguette", "Eiffel tower"]
},
{
name: "randomOne",
language: "Gibberish",
tags: ["random", "plant, bag"]
},
{
name: "bliep",
language: "English",
tags: ["lamp", "table, bed, oven"]
}
]
};
const result = [];
jsondata.elements.forEach(elem => {
if (elem.tags.includes("random")) {
result.push(elem.name);
}
});
console.log(result); // [ 'randomOne' ]
I have tried this question and able to get the names whose having 'random' in collection array.
$.elements[?(#.tags.indexOf('random') != -1)].name
Please update if it serves your purpose.

How to split JSON into Dataset rows?

I have the following JSON input data:
{
"lib": [
{
"id": "a1",
"type": "push",
"icons": [
{
"iId": "111"
}
],
"id": "a2",
"type": "pull",
"icons": [
{
"iId": "111"
},
{
"iId": "222"
}
]
}
]
I want to get the following Dataset:
id type iId
a1 push 111
a2 pull 111
a2 pull 222
How can I do it?
This is my current code. I use Spark 2.3 and Java 1.8:
ds = spark
.read()
.option("multiLine", true).option("mode", "PERMISSIVE")
.json(jsonFilePath);
ds = ds
.select(org.apache.spark.sql.functions.explode(ds.col("lib.icons")).as("icons"));
However the result is wrong:
+---------------+
| icons|
+---------------+
| [[111]]|
|[[111], [222...|
+---------------+
How can I get the correct Dataset?
UPDATE:
I tries this code, but it generates some extra combinations of id, type and iId that do not exist in the input file.
ds = ds
.withColumn("icons", org.apache.spark.sql.functions.explode(ds.col("lib.icons")))
.withColumn("id", org.apache.spark.sql.functions.explode(ds.col("lib.id")))
.withColumn("type", org.apache.spark.sql.functions.explode(ds.col("lib.type")));
ds = ds.withColumn("its", org.apache.spark.sql.functions.explode(ds.col("icons")));
As already pointed out, the JSON String seems to be malformed. with the updated one, you can use the following to get result you wanted:
import org.apache.spark.sql.functions._
spark.read
.format("json")
.load("in/test.json")
.select(explode($"lib").alias("result"))
.select($"result.id", $"result.type", explode($"result.icons").alias("iId"))
.select($"id", $"type", $"iId.iId")
.show
Your JSON appears to be malformed. Fixing the indenting makes this slightly more apparent:
{
"lib": [
{
"id": "a1",
"type": "push",
"icons": [
{
"iId": "111"
}
],
"id": "a2",
"type": "pull",
"icons": [
{
"iId": "111"
},
{
"iId": "222"
}
]
}
]
Does your code work correctly if you feed it this JSON instead?
{
"lib": [
{
"id": "a1",
"type": "push",
"icons": [
{
"iId": "111"
}
]
},
{
"id": "a2",
"type": "pull",
"icons": [
{
"iId": "111"
},
{
"iId": "222"
}
]
}
]
}
Note the inserted }, { just before "id": "a2" to break the object with duplicate keys into two, and the closing } at the very end which had previously been omitted.

Serialization of Chart configuration in Vaadin

I use Vaadin 7. I want to save a Chart configuration and restore it later. I found an interesting thing in com.vaadin.addon.charts.model.Configuration is that you can serialize the configuration into JSON object.
Code :
chart.getConfiguration().toString();
Result:
{
"type": "column"
},
"title": {
"text": "Chart"
},
"xAxis": {
"categories": [
"f",
"e"
],
"axisIndex": 0
},
"yAxis": {
"min": 0,
"title": {
"text": "Quantity"
},
"axisIndex": 0
},
"tooltip": {
"_fn_formatter": "this.series.name +\u0027: \u0027+ this.y +\u0027 (\u0027+ Math.round(this.percentage) +\u0027%)\u0027"
},
"plotOptions": {
"column": {
"stacking": "normal"
}
},
"series": [
{
"data": [
1,
2
],
"name": "d",
"visible": true
}
],
"exporting": {
"enabled": false
}
}
What I want now is build Configuration from that JSON object. Is there a way to that ?
Found it, pretty simple actually :
Chart chart = new Chart();
//json is the string containing your JSON object
chart.setJsonConfig(json);
//you'll have to draw the chart to update it if needed
//chart.drawChart();

Categories