How to merge two JSON string - java

I have two JSON strings, I want to merge these two response string into a single one. Is there any way to merge these two JSON string using java ?
String str1 = "{
"data" : {
"values" : {
"name" : "kiran",
"age" : "24"
}
}
}"
String str2 = "{
"data" : {
"values" : {
"name" : "Mamu",
"age" : "26"
}
}
}"
I wnat to merge these two JSON string as follows
String mergeResult = "{
"data" : {
"values" : [
{
"name" : "kiran",
"age" : "24"
},
{
"name" : "Manu",
"age" : "26"
}
]
}
}"

From your example JSON it looks like there can be many more input objects than two, so I'd use a JSON to JSON transform via JOLT library (https://github.com/bazaarvoice/jolt) as follows:
Form a JSON array of all the input {"data" : ...} objects (either by collecting the original objects and putting them in a List before serialization or just manually by concatenating their JSONs with square brackets):
[
{
"data": {
"values": {
"name": "kiran",
"age": "24"
}
}
},
{
"data": {
"values": {
"name": "Mamu",
"age": "26"
}
}
}
]
Use the JOLT spec:
[
{
"operation": "shift",
"spec": {
"*": {
"data": {
"values": {
"#": "data.values[]"
}
}
}
}
}
]
The resulting JSON:
{
"data" : {
"values" : [ {
"name" : "kiran",
"age" : "24"
}, {
"name" : "Mamu",
"age" : "26"
} ]
}
}
You can test or modify the spec yourself at http://jolt-demo.appspot.com before using it in your application.
Here's what Java side might look like:
Resource transformationSpec = ...
String inputJson = ...
List<Object> specs = JsonUtils.jsonToList(transformationSpec.getInputStream());
Chainr chainr = Chainr.fromSpec(specs);
Object inputObject = JsonUtils.jsonToObject(inputJson);
Object transformedObject = chainr.transform(inputObject);
String transformedJson = JsonUtils.toJsonString(transformedObject);

Library Josson & Jossons has concatenate operation to combine array from datasets.
https://github.com/octomix/josson
Jossons jossons = new Jossons();
jossons.putDataset("resp1", Josson.fromJsonString(
"{" +
" \"data\": {" +
" \"values\": {" +
" \"name\": \"kiran\"," +
" \"age\": \"24\"" +
" }" +
" }" +
"}"));
jossons.putDataset("resp2", Josson.fromJsonString(
"{" +
" \"data\": {" +
" \"values\": {" +
" \"name\": \"Mamu\"," +
" \"age\": \"26\"" +
" }" +
" }" +
"}"));
JsonNode mergeValues = jossons.evaluateQuery(
"resp1->data.toArray() <+< resp2->data.toArray()");
System.out.println(mergeValues.toPrettyString());
JsonNode mergeResult = Josson.create(mergeValues).getNode(
"toObject('values').toObject('data')");
System.out.println(mergeResult.toPrettyString());
mergeValues
[ {
"name" : "kiran",
"age" : "24"
}, {
"name" : "Mamu",
"age" : "26"
} ]
mergeResult
{
"data" : {
"values" : [ {
"name" : "kiran",
"age" : "24"
}, {
"name" : "Mamu",
"age" : "26"
} ]
}
}

May be not the most efficient solution but very simple one would be to parse each String into a Map (or specific POJO if you have one) and merge them as maps, and than serialize back into Json String. To parse a json string to map or a specific POJO you can use Jackson library - method readValue() of ObjectMapper Or Gson library. Also, I wrote my own simple wrapper over Jackson library that simplifies the use. Class JsonUtils is available as part of MgntUtils library (written and maintained by me). This class just has the methods that allow you to parse and de-serialize from/to Json String from/to a class instance. So your code could be as follows:
public String mergeJsonStrings(String str1, Str2) throws IOException {
Map<String, Object> map1 = convertJsonStringToMap(str1);
Map<String, Object> map2 = convertJsonStringToMap(str2);
Map<String, Object> dataMap1 = (Map<String, Object>)map1.get("data");
Map<String, Object> valuesMap1 = (Map<String, Object>)dataMap1.get("values");
Map<String, Object> dataMap2 = (Map<String, Object>)map2.get("data");
Map<String, Object> valuesMap2 = (Map<String, Object>)dataMap2.get("values");
valuesMap1.putAll(valuesMap2);
return convertMapToJsonString(map1);
}
Map<String, Object> convertJsonStringToMap(String str) throws IOException {
return JsonUtils.readObjectFromJsonString(str, Map.class);
}
Strong convertMapToJsonString(Map<String,Object> map) throws JsonProcessingException{
return JsonUtils.writeObjectToJsonString(map);
}
This example uses MgntUtils library to parse and serialize JSON but of course you can use Jackson, Gson or any other library you want. MgntUtils library available as Maven artifact and on Github (including source code and Javadoc)

Related

Transform JSON and create new one

I'm working with JSON in Java, and I want to trasnform a JSON I have as entry :
{
"index":{
"mutlipleIndices":[
{
"index":"languages",
"values":[
"English",
"German"
]
},
{
"index":"editors",
"values":[
"AC. Renus",
"Lodiga"
]
}
],
"simpleIndices":[
{
"index":"bookName",
"values":"A song Of Ice and fire"
},
{
"index":"nbPages",
"valeurs":1600
}
]
}
}
int this :
{
"data": { ... Put here the entry JSON ... },
"flatData": [
{
"key": "languages",
"type": "string",
"key_type": "languages.string",
"value_string": ["English", "German"]
},
{
"key": "editors",
"type": "string",
"key_type": "editors.string",
"value_string": ["AC. Renus", "Lodiga"]
},
{
"key": "bookName",
"type": "string",
"key_type": "bookName.string",
"value_string": "A song Of Ice and fire"
},
{
"key": "nbPages",
"type": "float",
"key_type": "nbPages.float",
"value_float": 1600
}
]
}
My entry JSON is a JsonNode (Jackson library), how can I iterate on that object and create a new one ?
Basically what I thought I'd do is iternate on the entry json, find an entry and transform it
Thanks in advance
Create 2 pojos
Mapping the input json (let's call it MyJsonInput.java)
Mapping the output you want (let's call it MyOutputObject.java).
These 2 classes should have fields which matches the json structure.
Create a mapper:
ObjectMapper objectMapper = new ObjectMapper();
Read the json and translate it into your object:
MyJsonInput myInput = objectMapper.readValue(json, MyJsonInput.class); //where json is a string with the content of your json file.
Now you have a MyJsonInput instance (myInput) containing the json data and you can do your logic to flatten it and fill your MyOutputObject.
To get the json string of MyOutputObject instance use:
String outputAsString = objectMapper.writeValueAsString(myOutputObject);
You can also threat your both input and output as a generic Map<String,Object> but in my opinion not the best way because it can get very complicated reading and parsing maps containing other maps, and not to mention that you need to cast your data into the appropriate type (string, number etc..)
https://github.com/octomix/josson
https://mvnrepository.com/artifact/com.octomix.josson/josson
implementation 'com.octomix.josson:josson:1.3.21'
-------------------------------------------------
Jossons jossons = new Jossons();
jossons.putDataset("input", Josson.fromJsonString(
"{\n" +
" \"index\":{\n" +
" \"multipleIndices\":[\n" +
" {\n" +
" \"index\":\"languages\",\n" +
" \"values\":[\n" +
" \"English\",\n" +
" \"German\"\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"index\":\"editors\",\n" +
" \"values\":[\n" +
" \"AC. Renus\",\n" +
" \"Lodiga\"\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"simpleIndices\":[\n" +
" {\n" +
" \"index\":\"bookName\",\n" +
" \"values\":\"A song Of Ice and fire\"\n" +
" },\n" +
" {\n" +
" \"index\":\"nbPages\",\n" +
" \"values\":1600\n" +
" }\n" +
" ]\n" +
" }\n" +
"}"));
Map<String, String> dictionaryFinder = new HashMap<>();
// Define a dictionary function, $0 is the function parameter.
dictionaryFinder.put("flatIndices()",
"$0->map(" +
"key:index," +
"type:if(values.isArray(),values[0],values).if(isText(),'string','float')," +
"key_type:concat(index,'.',if(values.isArray(),values[0],values).if(isText(),'string','float'))," +
"value_string:values)");
// Define a left concatenate operation to combine two arrays.
dictionaryFinder.put("allIndices",
"flatIndices(input->index.multipleIndices) <+< flatIndices(input->index.simpleIndices)");
ResolverProgress progress = new ResolverProgress("\nProgress:");
// The query is a left concatenate operation to combine two objects.
JsonNode output = jossons.evaluateQueryWithResolver(
"input->toObject('data') <+< allIndices->toObject('flatData')",
dictionaryFinder::get, null, progress);
// Print result.
System.out.println(output == null ? null : output.toPrettyString());
// Print resolution progress.
System.out.println(String.join("\n", progress.getSteps()));
Output
{
"data" : {
"index" : {
"multipleIndices" : [ {
"index" : "languages",
"values" : [ "English", "German" ]
}, {
"index" : "editors",
"values" : [ "AC. Renus", "Lodiga" ]
} ],
"simpleIndices" : [ {
"index" : "bookName",
"values" : "A song Of Ice and fire"
}, {
"index" : "nbPages",
"values" : 1600
} ]
}
},
"flatData" : [ {
"key" : "languages",
"type" : "string",
"key_type" : "languages.string",
"value_string" : [ "English", "German" ]
}, {
"key" : "editors",
"type" : "string",
"key_type" : "editors.string",
"value_string" : [ "AC. Renus", "Lodiga" ]
}, {
"key" : "bookName",
"type" : "string",
"key_type" : "bookName.string",
"value_string" : "A song Of Ice and fire"
}, {
"key" : "nbPages",
"type" : "float",
"key_type" : "nbPages.float",
"value_string" : 1600
} ]
}
Progress:
Round 1 : Resolving allIndices from flatIndices(input->index.multipleIndices) <+< flatIndices(input->index.simpleIndices)
Round 1 : Resolving flatIndices(input->index.multipleIndices) from $0->map(key:index,type:if(values.isArray(),values[0],values).if(isText(),'string','float'),key_type:concat(index,'.',if(values.isArray(),values[0],values).if(isText(),'string','float')),value_string:values)
Round 1 : Resolved flatIndices(input->index.multipleIndices) = Array with 2 elements
Round 2 : Resolving flatIndices(input->index.simpleIndices) from $0->map(key:index,type:if(values.isArray(),values[0],values).if(isText(),'string','float'),key_type:concat(index,'.',if(values.isArray(),values[0],values).if(isText(),'string','float')),value_string:values)
Round 2 : Resolved flatIndices(input->index.simpleIndices) = Array with 2 elements
Round 3 : Resolved allIndices = Array with 4 elements
Round 4 : Resolved query result = Object with 2 elements

Chainr.transform giving Null as transformedObject

I'm working on a requirement to convert JSONObject from one to another with the help of Jolt.
The source input i'm passing as :
{
"a":"ABC",
"b":"ABC1",
"c":1,
"d":2,
"e":"ABC2",
"details":
{
"a1": "ABC3",
"b1": "ABC4",
"c1": 3,
"d1": "ABC5",
"e1": "ABC6",
"f1": "ABC7"
}
}
I need in form of
{
"ConvertedOutput" : {
"X1" : "ABC1",
"Y1" : "ABC4"
}
}
Spec i used :
[
{
"operation": "shift",
"spec": {
"b": "ConvertedOutput.X1",
"details": {
"b1": "ConvertedOutput.Y1"
}
}
}
]
I'm able to get the proper output from : https://jolt-demo.appspot.com/#inception. But when i use same spec via code Chainr.transform returning null.
Code part
List<Object> transformJsonSpec = JsonUtils.classpathToList("inputSpecJSONPath");
final Chainr chainr = Chainr.fromSpec(transformJsonSpec);
Object transformedOutput = chainr.transform(payload);
System.out.println("transformSpec Str " + transformJsonSpec.toString());
System.out.println("transformSpec " + transformJsonSpec);
System.out.println("transformedOutput " + transformedOutput);
System.out.println(" jolt transform " + JsonUtils.toJsonString(transformedOutput));
The payload needs to be converted using JsonUtils.jsonToObject if you are passing in a String:
Object transformedOutput = chainr.transform(JsonUtils.jsonToObject(payload));

How to get values of keys of inside array in json array

This is the string that I get which I want to parse as json and get the values of "s", "o", "c" and "p" .
{
"head": {
"vars": [
"s",
"c",
"o",
"p"
]
},
"results": {
"bindings": [
{
"s": {
"type": "uri",
"value": "http://example.org/data/window"
},
"c": {
"type": "uri",
"value": "http://www.w3.org/ns/sosa/FeatureOfInterest"
},
"o": {
"type": "uri",
"value": "http://example.org/data/window104state"
},
"p": {
"type": "uri",
"value": "http://www.w3.org/ns/ssn/hasProperty"
}
},
{
"s": {
"type": "uri",
"value": "http://example.org/data/earth"
},
"c": {
"type": "uri",
"value": "http://www.w3.org/ns/sosa/FeatureOfInterest"
},
"o": {
"type": "uri",
"value": "http://example.org/data/VCAB-DP1-BP-40location"
},
"p": {
"type": "uri",
"value": "http://www.w3.org/ns/sosa/hasSample"
}
}
]
}
}
This is the code I have tried so far:
JsonParser jsonParser = new JsonParser();
JsonElement element = jsonParser.parse(str);
JsonObject obj = element.getAsJsonObject();
JsonObject results = obj.get("results").getAsJsonObject();
for(Map.Entry<String, JsonElement> entry : results.entrySet()) {
JsonArray array = entry.getValue().getAsJsonObject().getAsJsonArray("bindings");
for (JsonElement jsonElement : array) {
for (Map.Entry<String, JsonElement> entry1 : jsonElement.getAsJsonObject().entrySet()) {
System.out.println("Key = " + entry1.getKey() + " Value = " + entry1.getValue() );
}
}
What I want to get is the values of the inside array as such:
"s": "http://example.org/data/earth"
"c": "http://www.w3.org/ns/sosa/FeatureOfInterest"
etc.
Instead I get an error:
Exception in thread "main" java.lang.IllegalStateException: Not a JSON Object: [{"s":{"type":"uri","value":"http://example.org/data/window"},"c":{"type":"uri","value":"http://www.w3.org/ns/sosa/FeatureOfInterest"},"o":{"type":"uri","value":"http://example.org/data/window104state"},
(the whole string).
UPDATE
Thanks to #Deadpool I managed to get the values but now I need to get the "inner" values of the bindings meaning the "value" part of each binding(s,c,p and o). I need only this part and not the "type" part.
This is the result thanks to #Deadpool:
Key = s Value = {"type":"uri","value":"http://example.org/data/window"}
Key = c Value = {"type":"uri","value":"http://www.w3.org/ns/sosa/FeatureOfInterest"}
Key = p Value = {"type":"uri","value":"http://www.w3.org/ns/ssn/hasProperty"}
Key = o Value = {"type":"uri","value":"http://example.org/data/window104state"}
SOLUTION
OK for those interested I managed to get it this the statement that was needed:
System.out.println("Key = " + entry1.getKey() + " Value = " + entry1.getValue().getAsJsonObject().get("value"));
And this is the desired result:
Key = s Value = "http://example.org/data/earth"
Key = c Value = "http://www.w3.org/ns/sosa/FeatureOfInterest"
Key = o Value = "http://example.org/data/VCAB-DP1-BP-40location"
Key = p Value = "http://www.w3.org/ns/sosa/hasSample"
The problem is in this statement bindings is a JsonArray, get it as JsonArray directly
JsonArray array = entry.getValue().getAsJsonObject().getAsJsonArray("bindings");
Solution
for(Map.Entry<String, JsonElement> entry : results.entrySet()) {
JsonArray array = entry.getValue().getAsJsonArray();
for (JsonElement jsonElement : array) {
for (Map.Entry<String, JsonElement> entry1 : jsonElement.getAsJsonObject().entrySet()) {
System.out.println("Key = " + entry1.getKey() + " Value = " + entry1.getValue() );
}
}
You can use Declarative Stream Mapping (DSM) stream parsing library to easily capture data from XML or JSON
First of all, you must define the mapping between JSON data and your fields in yaml or JSON format.
Here are the mapping definitions:
result:
type: array
path: /results/bindings/(s|c|o|p) // regex
fields:
key:
path: type
value:
Java class that you want to deserialize:
public class KeyValue{
public String key;
public String value
}
Java Code to parse JSON:
DSM dsm=new DSMBuilder(new File("path/to/mapping.yaml")).create(KeyValue.class);
List<KeyValue> list= (List<KeyValue>)dsm.toObject(jsonData);
// write root object as json
dsm.getObjectMapper().writerWithDefaultPrettyPrinter().writeValue(System.out, list);
Here is output:
[ {
"key" : "uri",
"value" : "http://example.org/data/window"
}, {
"key" : "uri",
"value" : "http://www.w3.org/ns/sosa/FeatureOfInterest"
}, {
"key" : "uri",
"value" : "http://example.org/data/window104state"
}, {
"key" : "uri",
"value" : "http://www.w3.org/ns/ssn/hasProperty"
}, {
"key" : "uri",
"value" : "http://example.org/data/earth"
}, {
"key" : "uri",
"value" : "http://www.w3.org/ns/sosa/FeatureOfInterest"
}, {
"key" : "uri",
"value" : "http://example.org/data/VCAB-DP1-BP-40location"
}, {
"key" : "uri",
"value" : "http://www.w3.org/ns/sosa/hasSample"
} ]

JSON to JSON Transform of input sample using any existing java library/tools

Input:
{
"Student": {
"name" :"abc",
"id" : 588,
"class : "12"
}
}
Reqired Output:
{
"Student": {
"key" :"name",
"value":"abc",
"key" :"id",
"value":"588",
"key" :"class",
"value":"12"
}
}
Your output json invalid. Json object can not duplicate key .
You can use the library org.json and do something like this:
JSONObject jsonObject = new JSONObject(inputJson);
JSONObject outputJson = new JSONObject();
JSONArray array = new JSONArray();
for (Object key : jsonObject.keySet()) {
JSONObject item = new JSONObject();
String keyStr = (String)key;
Object keyvalue = jsonObj.get(keyStr);
item.put(keyStr, keyvalue);
array.put(item);
}
outputJson.put("Student", array);
System.out.println(json.toString());
Output :
{
"Student": [
{
"key": "name",
"value": "abc"
},
{
"key": "id",
"value": "588"
},
{
"key": "class",
"value": "12"
}
]
}
Similar to the other answer, the desired output JSON format is not valid.
The closest valid output would be
{
"Student" : [ {
"key" : "name",
"value" : "abc"
}, {
"key" : "id",
"value" : 588
}, {
"key" : "class",
"value" : "12"
} ]
}
This can be generated via Jolt with the following spec
[
{
"operation": "shift",
"spec": {
"Student": {
"name": {
"$": "Student[0].key",
"#": "Student[0].value"
},
"id": {
"$": "Student[1].key",
"#": "Student[1].value"
},
"class": {
"$": "Student[2].key",
"#": "Student[2].value"
}
}
}
}
]
This is easy to solve with JSLT if we assume the output is made valid JSON by making an array of key/value objects like the other respondents do.
The array function converts an object into an array of key/value objects exactly like you ask for, so the transform becomes:
{"Student" : array(.Student)}

Read out elements of a string in specific order

For some reasons I have to use a specific string in my project. This is the text file (it's a JSON File):
{"algorithm":
[
{ "key": "onGapLeft", "value" : "moveLeft" },
{ "key": "onGapFront", "value" : "moveForward" },
{ "key": "onGapRight", "value" : "moveRight" },
{ "key": "default", "value" : "moveBackward" }
]
}
I've defined it in JAVA like this:
static String input = "{\"algorithm\": \n"+
"[ \n" +
"{ \"key\": \"onGapLeft\", \"value\" : \"moveLeft\" }, \n" +
"{ \"key\": \"onGapFront\", \"value\" : \"moveForward\" }, \n" +
"{ \"key\": \"onGapRight\", \"value\" : \"moveRight\" }, \n" +
"{ \"key\": \"default\", \"value\" : \"moveBackward\" } \n" +
"] \n" +
"}";
Now I have to isolate the keys and values in an array:
key[0] = onGapLeft; value[0] = moveLeft;
key[1] = onGapFront; value[1] = moveForward;
key[2] = onGapRight; value[2] = moveRight;
key[3] = default; value[3] = moveBackward;
I'm new to JAVA and don't understand the string class very well. Is there an easy way to get to that result? You would help me really!
Thanks!
UPDATE:
I didn't explained it well enough, sorry. This program will run on a LEGO NXT Robot. JSON won't work there as I want it to so I have to interpret this JSON File as a normal STRING! Hope that explains what I want :)
I propose a solution in several step.
1) Let's get the different parts of your ~JSON String. We will use a pattern to get the different {.*} parts :
public static void main(String[] args) throws Exception{
List<String> lines = new ArrayList<String>();
Pattern p = Pattern.compile("\\{.*\\}");
Matcher matcher = p.matcher(input);
while (matcher.find()) {
lines.add(matcher.group());
}
}
(you should take a look at Pattern and Matcher)
Now, lines contains 4 String :
{ "key": "onGapLeft", "value" : "moveLeft" }
{ "key": "onGapFront", "value" : "moveForward" }
{ "key": "onGapRight", "value" : "moveRight" }
{ "key": "default", "value" : "moveBackward" }
Given a String like one of those, you can remove curly brackets with a call to String#replaceAll();
List<String> cleanLines = new ArrayList<String>();
for(String line : lines) {
//replace curly brackets with... nothing.
//added a call to trim() in order to remove whitespace characters.
cleanLines.add(line.replaceAll("[{}]","").trim());
}
(You should take a look at String String#replaceAll(String regex))
Now, cleanLines contains :
"key": "onGapLeft", "value" : "moveLeft"
"key": "onGapFront", "value" : "moveForward"
"key": "onGapRight", "value" : "moveRight"
"key": "default", "value" : "moveBackward"
2) Let's parse one of those lines :
Given a line like :
"key": "onGapLeft", "value" : "moveLeft"
You can split it on , character using String#split(). It will give you a String[] containing 2 elements :
//parts[0] = "key": "onGapLeft"
//parts[1] = "value" : "moveLeft"
String[] parts = line.split(",");
(You should take a look at String[] String#split(String regex))
Let's clean those parts (remove "") and assign them to some variables:
String keyStr = parts[0].replaceAll("\"","").trim(); //Now, key = key: onGapLeft
String valueStr = parts[1].replaceAll("\"","").trim();//Now, value = value : moveLeft
//Then, you split `key: onGapLeft` with character `:`
String key = keyStr.split(":")[1].trim();
//And the same for `value : moveLeft` :
String value = valueStr.split(":")[1].trim();
That's it !
You should also take a look at Oracle's tutorial on regular expressions (This one is really important and you should invest time on it).
You need to use a JSON parser library here. For example, with org.json you could parse it as
String input = "{\"algorithm\": \n"+
"[ \n" +
"{ \"key\": \"onGapLeft\", \"value\" : \"moveLeft\" }, \n" +
"{ \"key\": \"onGapFront\", \"value\" : \"moveForward\" }, \n" +
"{ \"key\": \"onGapRight\", \"value\" : \"moveRight\" }, \n" +
"{ \"key\": \"default\", \"value\" : \"moveBackward\" } \n" +
"] \n" +
"}";
JSONObject root = new JSONObject(input);
JSONArray map = root.getJSONArray("algorithm");
for (int i = 0; i < map.length(); i++) {
JSONObject entry = map.getJSONObject(i);
System.out.println(entry.getString("key") + ": "
+ entry.getString("value"));
}
Output :
onGapLeft: moveLeft
onGapFront: moveForward
onGapRight: moveRight
default: moveBackward

Categories