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
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");
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");
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.
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.
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();