I'm trying to parse Json string using java, I have stuck up with some scenario.
See below is my JSON String:
"NetworkSettings": {
"Ports": {
"8080/tcp": [ // It will change dynamically like ("8125/udp" and "8080/udp" etc....)
{
"HostIp": "0.0.0.0",
"HostPort": "8080"
}
]
}
}
I try to parse the above json string by using the following code:
JsonObject NetworkSettings_obj=(JsonObject)obj.get("NetworkSettings");
if(NetworkSettings_obj.has("Ports"))
{
JsonObject ntw_Ports_obj=(JsonObject)NetworkSettings_obj.get("Ports");
if(ntw_Ports_obj.has("8080/tcp"))
{
JsonArray arr_ntwtcp=(JsonArray)ntw_Ports_obj.get("8080/tcp");
JsonObject ntwtcp_obj=arr_ntwtcp.get(0).getAsJsonObject();
if(ntwtcp_obj.has("HostIp"))
{
ntw_HostIp=ntwtcp_obj.get("HostIp").toString();
System.out.println("Network HostIp = "+ntw_HostIp);
}
if(ntwtcp_obj.has("HostPort"))
{
ntw_HostPort=ntwtcp_obj.get("HostPort").toString();
System.out.println("Network HostPort = "+ntw_HostPort);
}
}
else
{
ntw_HostIp="NA";
ntw_HostPort="NA";
}
}
else
{
ntw_HostIp="NA";
ntw_HostPort="NA";
}
In my code I have used this code
JsonArray arr_ntwtcp=(JsonArray)ntw_Ports_obj.get("8080/tcp");
to get the value of "8080/tcp"
How can I get the values of dynamically changing key like ("8125/udp","8134/udp", etc...)
Note: I'm using gson library for parsing
After modification
public static void main(String args[])
{
try
{
JsonParser parser = new JsonParser();
JsonObject obj=(JsonObject)parser.parse(new FileReader("sampleJson.txt"));
System.out.println("obj = "+obj);
JsonObject NetworkSettings_obj=(JsonObject)obj.get("NetworkSettings");
if(NetworkSettings_obj.has("Ports"))
{
JsonObject ntw_Ports_obj=(JsonObject)NetworkSettings_obj.get("Ports");
System.out.println("ntw_Ports_obj = "+ntw_Ports_obj);
Object keyObjects = new Gson().fromJson(ntw_Ports_obj, Object.class);
List keys = new ArrayList();
System.out.println(keyObjects instanceof Map); //**** here the statement prints false
if (keyObjects instanceof Map) // *** so controls doesn't enters into the if() condition block *** //
{
Map map = (Map) keyObjects;
System.out.println("Map = "+map);
keys.addAll(map.keySet());
String key = (String) keys.get(0);
JsonArray jArray = (JsonArray) ntw_Ports_obj.get(key);
System.out.println("Array List = "+jArray);
}
}
}
catch(Exception e)
{
}
}
You can do something like that (not tested but should be ok) :
if (ntw_Ports_obj.isJsonArray()) {
Iterator it = ntw_Ports_obj.getAsJsonArray().iterator();
while (it.hasNext()) {
JsonElement element = (JsonElement) it.next();
if(element.isJsonArray()){
JsonArray currentArray = element.getAsJsonArray();
// Do something with the new JsonArray...
}
}
}
So your problem is the key 8080/tcp is not fixed and it may change. when this situation you can try like this to get the value of the Dynamic key.
Set<Map.Entry<String, JsonElement>> entrySet = ntw_Ports_obj
.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
String key = entry.getKey();
JsonArray jArray = (JsonArray) ntw_Ports_obj.get(key);
System.out.println(jArray);
}
Edit:
Object keyObjects = new Gson().fromJson(ntw_Ports_obj, Object.class);
List keys = new ArrayList();
/** for the given json there is a one json object within the 'Ports' so the 'keyObjects' will be the 'Map'**/
if (keyObjects instanceof Map) {
Map map = (Map) keyObjects;
keys.addAll(map.keySet());
/**
* keys is a List it may contain more than 1 value, but for the given
* json it will contain only one value
**/
String key = (String) keys.get(0);
JsonArray jArray = (JsonArray) ntw_Ports_obj.get(key);
System.out.println(jArray);
}
I am trying to iterate over a json object using json simple. I have seen answers where you can do a getJSONObject("child") from
{ "child": { "something": "value", "something2": "value" } }
But what if I just have something
{
"k1":"v1",
"k2":"v2",
"k3":"v3"
}
And want to iterate over that json object. This:
Iterator iter = jObj.keys();
Throws:
cannot find symbol
symbol : method keys()
location: class org.json.simple.JSONObject
Assuming your JSON object is saved in a file "simple.json", you can iterate over the attribute-value pairs as follows:
JSONParser parser = new JSONParser();
Object obj = parser.parse(new FileReader("simple.json"));
JSONObject jsonObject = (JSONObject) obj;
for(Iterator iterator = jsonObject.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
System.out.println(jsonObject.get(key));
}
You can do like this
String jsonstring = "{ \"child\": { \"something\": \"value\", \"something2\": \"value\" } }";
JSONObject resobj = new JSONObject(jsonstring);
Iterator<?> keys = resobj.keys().iterator();
while(keys.hasNext() ) {
String key = (String)keys.next();
if ( resobj.get(key) instanceof JSONObject ) {
JSONObject xx = new JSONObject(resobj.get(key).toString());
Log.d("res1",xx.getString("something"));
Log.d("res2",xx.getString("something2"));
}
}
In Java 8 we can use lambdas
void handleJSONObject(JSONObject jsonObject) {
jsonObject.keys().forEachRemaining(key -> {
Object value = jsonObject.get(key);
logger.info("Key: {0}\tValue: {1}", key, value);
}
}
Below is the code to iterate through org.google.jso.JsonElemet set and filter out the specific JsonElement by key:
Predicate<Map.Entry<String, JsonElement>> keyPredicate = a -> a.getKey().equalsIgnoreCase(jsonAttributeKey);
Predicate<Map.Entry<String, JsonElement>> valuePredicate = a -> a.getValue()!= null && !a.getValue().isJsonNull();
return responseJson.getAsJsonObject().entrySet().stream()
.filter(keyPredicate.and((valuePredicate)))
.findAny()
.orElseThrow(() -> {
System.out.println(jsonAttributeKey +" tag not exist in the json");
return NGPExceptionFactory.getNGPException(errorCode);
})
.getValue();
I'm new to JSON manipulation in Java and I have a String in the form of a JSON Array with several layers I need to access and put into class attributes. For example, here's my JSON object:
{"JsonObject" : [{"attributeOne":"valueOne",
"attributeTwo":"valueTwo",
"attributeThree":[{"subAttributeOne":"subValueOne",
"subAttributeTwo":"subValueTwo"}],
"attributeFour":[{"subAttributeOne":"subValueThree",
"subAttributeTwo":"subValueFour"}],
"attributeFive":"valueThree"},
{"attributeOne":"valueFour",
"attributeTwo":"valueFive",
"attributeThree":[{"subAttributeOne":"subValueFive",
"subAttributeTwo":"subValueSix"}],
"attributeFour":[{"subAttributeOne":"subValueSeven",
"subAttributeTwo":"subValueEight"}],
"attributeFive":"valueSix"}]}
Lets say I have a class called MyClass that has these attributes, how would i parse this string, knowing this is an array of n Objects, each containing "attributeOne, attributeTwo, ..., attributeFive"?
Here's what I have so far:
public MyClass[] jsonToJava (String jsonObj)
{
ArrayList<MyClass> myClassArray = new ArrayList<MyClass>();
//Somehow create a JSONArray from my jsonObj String
JSONArray jsonArr = new JSONArray(jsonObj); //Don't know if this would be correct
for(int i=0; i<jsonArr.length; i++){
MyClass myClassObject = new MyClass();
myClassObject.setAttributeOne = jsonArr[i].getString("attributeOne");
// How can I access the subAttributeOne and Two under attributeThree and Four?
// add all other values to myClassObject
myClassArray.add(myClassObject);
}
return myClassArray;
}
As you can probably tell, I'm fairly new to programming :P Thanks in advance for the help!
Try Jackson JSON:
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
User user = mapper.readValue(jsonObj, User.class); //method overloaded to take String
grabbed this two liner from:
http://wiki.fasterxml.com/JacksonInFiveMinutes
http://jackson.codehaus.org/0.9.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html
Should convert your JSON strong to an object. In a Java EE context you may be able to get this unmarshalling functionality at an endpoint with the appropriate annotation.
The way you are trying to do it is painful and involved.
I would suggest that you use a library like GSON and let it do the heavy lifting.
http://code.google.com/p/google-gson/
The documentation has object examples: https://sites.google.com/site/gson/gson-user-guide#TOC-Object-Examples
For your example you can use recursion something like:
public Object getChild(Object parent, int index) {
if (parent instanceof JSONArray) {
try {
Object o = ( (JSONArray)parent ).get(index);
if( o instanceof JSONObject ){
parent = ((JSONObject) ( o ) ).getMap();
return parent;
}
if( o instanceof Double ){
parent = (Double) o;
return parent;
}
if( o instanceof Integer ){
parent = (Integer) o;
return parent;
}
....
} catch (JSONException e1) {
e1.printStackTrace();
}
}
if (parent instanceof JSONObject) {
parent = ( (JSONObject)parent ).getMap();
}
if (parent instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) parent;
Iterator<?> it = map.keySet().iterator();
for (int i=0; i<index; i++){
it.next();
}
return map.get(it.next());
}
else if (parent instanceof Collection<?>) {
Iterator<?> it = ((Collection<?>) parent).iterator();
for (int i=0; i<index; i++){
it.next();
}
return it.next();
}
//throw new IndexOutOfBoundsException("'" + parent + "'cannot have children!");
return null;
}
But its a bit complicated (+bad practice to use instanceof) and you don't want to reinvent the wheel. So use GSON or Jackson.
Gson gson = new Gson();
String myClassStr = gson.toGson(MyClassInstance);
....
Myclass yourClass = gson.fromJson(myClassStr, Myclass.class);
I have a json stream which can be something like :
{"intervention":
{
"id":"3",
"subject":"dddd",
"details":"dddd",
"beginDate":"2012-03-08T00:00:00+01:00",
"endDate":"2012-03-18T00:00:00+01:00",
"campus":
{
"id":"2",
"name":"paris"
}
}
}
or something like
{"intervention":
[{
"id":"1",
"subject":"android",
"details":"test",
"beginDate":"2012-03-26T00:00:00+02:00",
"endDate":"2012-04-09T00:00:00+02:00",
"campus":{
"id":"1",
"name":"lille"
}
},
{
"id":"2",
"subject":"lozlzozlo",
"details":"xxx",
"beginDate":"2012-03-14T00:00:00+01:00",
"endDate":"2012-03-18T00:00:00+01:00",
"campus":{
"id":"1",
"name":"lille"
}
}]
}
In my Java code I do the following:
JSONObject json = RestManager.getJSONfromURL(myuri); // retrieve the entire json stream
JSONArray interventionJsonArray = json.getJSONArray("intervention");
In the first case, the above doesn't work because there is only one element in the stream..
How do I check if the stream is an object or an array ?
I tried with json.length() but it didn't work..
Thanks
Something like this should do it:
JSONObject json;
Object intervention;
JSONArray interventionJsonArray;
JSONObject interventionObject;
json = RestManager.getJSONfromURL(myuri); // retrieve the entire json stream
Object intervention = json.get("intervention");
if (intervention instanceof JSONArray) {
// It's an array
interventionJsonArray = (JSONArray)intervention;
}
else if (intervention instanceof JSONObject) {
// It's an object
interventionObject = (JSONObject)intervention;
}
else {
// It's something else, like a string or number
}
This has the advantage of getting the property value from the main JSONObject just once. Since getting the property value involves walking a hash tree or similar, that's useful for performance (for what it's worth).
Maybe a check like this?
JSONObject intervention = json.optJSONObject("intervention");
This returns a JSONObject or null if the intervention object is not a JSON object. Next, do this:
JSONArray interventions;
if(intervention == null)
interventions=jsonObject.optJSONArray("intervention");
This will return you an array if it's a valid JSONArray or else it will give null.
To make it simple, you can just check first string from server result.
String result = EntityUtils.toString(httpResponse.getEntity()); //this function produce JSON
String firstChar = String.valueOf(result.charAt(0));
if (firstChar.equalsIgnoreCase("[")) {
//json array
}else{
//json object
}
This trick is just based on String of JSON format {foo : "bar"} (object)
or [ {foo : "bar"}, {foo: "bar2"} ] (array)
You can get the Object of the input string by using below code.
String data = "{ ... }";
Object json = new JSONTokener(data).nextValue();
if (json instanceof JSONObject)
//do something for JSONObject
else if (json instanceof JSONArray)
//do something for JSONArray
Link: https://developer.android.com/reference/org/json/JSONTokener#nextValue
Object valueObj = uiJSON.get(keyValue);
if (valueObj instanceof JSONObject) {
this.parseJSON((JSONObject) valueObj);
} else if (valueObj instanceof JSONArray) {
this.parseJSONArray((JSONArray) valueObj);
} else if(keyValue.equalsIgnoreCase("type")) {
this.addFlagKey((String) valueObj);
}
// ITERATE JSONARRAY
private void parseJSONArray(JSONArray jsonArray) throws JSONException {
for (Iterator iterator = jsonArray.iterator(); iterator.hasNext();) {
JSONObject object = (JSONObject) iterator.next();
this.parseJSON(object);
}
}
I haven't tryied it, but maybe...
JsonObject jRoot = RestManager.getJSONfromURL(myuri); // retrieve the entire json stream
JsonElement interventionElement = jRoot.get("intervention");
JsonArray interventionList = new JsonArray();
if(interventionElement.isJsonArray()) interventionList.addAll(interventionElement.getAsJsonArray());
else interventionList.add(interventionElement);
If it's a JsonArray object, just use getAsJsonArray() to cast it. If not, it's a single element so just add it.
Anyway, your first exemple is broken, you should ask server's owner to fix it. A JSON data structure must be consistent. It's not just because sometime intervention comes with only 1 element that it doesn't need to be an array. If it has only 1 element, it will be an array of only 1 element, but still must be an array, so that clients can parse it using always the same schema.
//returns boolean as true if it is JSONObject else returns boolean false
public static boolean returnBooleanBasedOnJsonObject(Object jsonVal){
boolean h = false;
try {
JSONObject j1=(JSONObject)jsonVal;
h=true;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
if(e.toString().contains("org.json.simple.JSONArray cannot be cast to org.json.simple.JSONObject")){
h=false;
}
}
return h;
}
I am consuming some JSON from two different sources, I end up with two JSONObjects and I'd like to combine them into one.
Data:
"Object1": {
"Stringkey":"StringVal",
"ArrayKey": [Data0, Data1]
}
"Object2": {
"Stringkey":"StringVal",
"Stringkey":"StringVal",
"Stringkey":"StringVal",
}
Code, using http://json.org/java/ library:
// jso1 and jso2 are some JSONObjects already instantiated
JSONObject Obj1 = (JSONObject) jso.get("Object1");
JSONObject Obj2 = (JSONObject) jso.get("Object2");
So in this situation I'd like to combine Obj1 and Obj2, either to make a totally new JSONObject or concat one to the other. Any ideas besides pulling them all apart and individually adding in by puts?
If you want a new object with two keys, Object1 and Object2, you can do:
JSONObject Obj1 = (JSONObject) jso1.get("Object1");
JSONObject Obj2 = (JSONObject) jso2.get("Object2");
JSONObject combined = new JSONObject();
combined.put("Object1", Obj1);
combined.put("Object2", Obj2);
If you want to merge them, so e.g. a top level object has 5 keys (Stringkey1, ArrayKey, StringKey2, StringKey3, StringKey4), I think you have to do that manually:
JSONObject merged = new JSONObject(Obj1, JSONObject.getNames(Obj1));
for(String key : JSONObject.getNames(Obj2))
{
merged.put(key, Obj2.get(key));
}
This would be a lot easier if JSONObject implemented Map, and supported putAll.
In some cases you need a deep merge, i.e., merge the contents of fields with identical names (just like when copying folders in Windows). This function may be helpful:
/**
* Merge "source" into "target". If fields have equal name, merge them recursively.
* #return the merged object (target).
*/
public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException {
for (String key: JSONObject.getNames(source)) {
Object value = source.get(key);
if (!target.has(key)) {
// new value for "key":
target.put(key, value);
} else {
// existing value for "key" - recursively deep merge:
if (value instanceof JSONObject) {
JSONObject valueJson = (JSONObject)value;
deepMerge(valueJson, target.getJSONObject(key));
} else {
target.put(key, value);
}
}
}
return target;
}
/**
* demo program
*/
public static void main(String[] args) throws JSONException {
JSONObject a = new JSONObject("{offer: {issue1: value1}, accept: true}");
JSONObject b = new JSONObject("{offer: {issue2: value2}, reject: false}");
System.out.println(a+ " + " + b+" = "+JsonUtils.deepMerge(a,b));
// prints:
// {"accept":true,"offer":{"issue1":"value1"}} + {"reject":false,"offer":{"issue2":"value2"}} = {"reject":false,"accept":true,"offer":{"issue1":"value1","issue2":"value2"}}
}
You can create a new JSONObject like this:
JSONObject merged = new JSONObject();
JSONObject[] objs = new JSONObject[] { Obj1, Obj2 };
for (JSONObject obj : objs) {
Iterator it = obj.keys();
while (it.hasNext()) {
String key = (String)it.next();
merged.put(key, obj.get(key));
}
}
With this code, if you have any repeated keys between Obj1 and Obj2 the value in Obj2 will remain. If you want the values in Obj1 to be kept you should invert the order of the array in line 2.
This wrapper method will help :
private static JSONObject merge(JSONObject... jsonObjects) throws JSONException {
JSONObject jsonObject = new JSONObject();
for(JSONObject temp : jsonObjects){
Iterator<String> keys = temp.keys();
while(keys.hasNext()){
String key = keys.next();
jsonObject.put(key, temp.get(key));
}
}
return jsonObject;
}
Thanks to Erel. Here is a Gson version.
/**
* Merge "source" into "target". If fields have equal name, merge them recursively.
* Null values in source will remove the field from the target.
* Override target values with source values
* Keys not supplied in source will remain unchanged in target
*
* #return the merged object (target).
*/
public static JsonObject deepMerge(JsonObject source, JsonObject target) throws Exception {
for (Map.Entry<String,JsonElement> sourceEntry : source.entrySet()) {
String key = sourceEntry.getKey();
JsonElement value = sourceEntry.getValue();
if (!target.has(key)) {
//target does not have the same key, so perhaps it should be added to target
if (!value.isJsonNull()) //well, only add if the source value is not null
target.add(key, value);
} else {
if (!value.isJsonNull()) {
if (value.isJsonObject()) {
//source value is json object, start deep merge
deepMerge(value.getAsJsonObject(), target.get(key).getAsJsonObject());
} else {
target.add(key,value);
}
} else {
target.remove(key);
}
}
}
return target;
}
/**
* simple test
*/
public static void main(String[] args) throws Exception {
JsonParser parser = new JsonParser();
JsonObject a = null;
JsonObject b = null;
a = parser.parse("{offer: {issue1: null, issue2: null}, accept: true, reject: null}").getAsJsonObject();
b = parser.parse("{offer: {issue2: value2}, reject: false}").getAsJsonObject();
System.out.println(deepMerge(a,b));
// prints:
// {"offer":{},"accept":true}
a = parser.parse("{offer: {issue1: value1}, accept: true, reject: null}").getAsJsonObject();
b = parser.parse("{offer: {issue2: value2}, reject: false}").getAsJsonObject();
System.out.println(deepMerge(a,b));
// prints:
// {"offer":{"issue2":"value2","issue1":"value1"},"accept":true}
}
A ready method to merge any number of JSONObjects:
/**
* Merges given JSONObjects. Values for identical key names are merged
* if they are objects, otherwise replaced by the latest occurence.
*
* #param jsons JSONObjects to merge.
*
* #return Merged JSONObject.
*/
public static JSONObject merge(
JSONObject[] jsons) {
JSONObject merged = new JSONObject();
Object parameter;
for (JSONObject added : jsons) {
for (String key : toStringArrayList(added.names())) {
try {
parameter = added.get(key);
if (merged.has(key)) {
// Duplicate key found:
if (added.get(key) instanceof JSONObject) {
// Object - allowed to merge:
parameter =
merge(
new JSONObject[]{
(JSONObject) merged.get(key),
(JSONObject) added.get(key)});
}
}
// Add or update value on duplicate key:
merged.put(
key,
parameter);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
return merged;
}
/**
* Convert JSONArray to ArrayList<String>.
*
* #param jsonArray Source JSONArray.
*
* #return Target ArrayList<String>.
*/
public static ArrayList<String> toStringArrayList(JSONArray jsonArray) {
ArrayList<String> stringArray = new ArrayList<String>();
int arrayIndex;
for (
arrayIndex = 0;
arrayIndex < jsonArray.length();
arrayIndex++) {
try {
stringArray.add(
jsonArray.getString(arrayIndex));
} catch (JSONException e) {
e.printStackTrace();
}
}
return stringArray;
}
This is what I do
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* This class has all static functions to merge 2 objects into one
*/
public class MergeHelper {
private static ObjectMapper objectMapper = new ObjectMapper();
/**
* return a merge JsonNode, merge newJson into oldJson; override or insert
* fields from newJson into oldJson
*
* #param oldJson
* #param newJson
* #return
*/
public static JsonNode mergeJsonObject(JsonNode oldJson, JsonNode newJson) {
ObjectNode merged = objectMapper.createObjectNode();
merged.setAll((ObjectNode) oldJson);
merged.setAll((ObjectNode) newJson);
return merged;
}
}
For me that function worked:
private static JSONObject concatJSONS(JSONObject json, JSONObject obj) {
JSONObject result = new JSONObject();
for(Object key: json.keySet()) {
System.out.println("adding " + key + " to result json");
result.put(key, json.get(key));
}
for(Object key: obj.keySet()) {
System.out.println("adding " + key + " to result json");
result.put(key, obj.get(key));
}
return result;
}
(notice) - this implementation of concataion of json is for import
org.json.simple.JSONObject;
It's a while from the question but now JSONObject implements "toMap" method so you can try this way:
Map<String, Object> map = Obj1.toMap(); //making an HashMap from obj1
map.putAll(Obj2.toMap()); //moving all the stuff from obj2 to map
JSONObject combined = new JSONObject( map ); //new json from map
In addition to #erel's answer, I had to make this edit (I'm using org.json.simple) to the outer else for dealing with JSONArray's:
// existing value for "key" - recursively deep merge:
if (value instanceof JSONObject) {
JSONObject valueJson = (JSONObject)value;
deepMerge(valueJson, (JSONObject) target.get(key));
}
// insert each JSONArray's JSONObject in place
if (value instanceof JSONArray) {
((JSONArray) value).forEach(
jsonobj ->
((JSONArray) target.get(key)).add(jsonobj));
}
else {
target.put(key, value);
}
I used string to concatenate new object to an existing object.
private static void concatJSON() throws IOException, InterruptedException {
JSONParser parser = new JSONParser();
Object obj = parser.parse(new FileReader(new File(Main.class.getResource("/file/user.json").toURI())));
JSONObject jsonObj = (JSONObject) obj; //usernameJsonObj
String [] values = {"0.9" , Date.from(Calendar.getInstance().toInstant()).toLocaleString()},
innermost = {"Accomplished", "LatestDate"},
inner = {"Lesson1", "Lesson2", "Lesson3", "Lesson4"};
String in = "Jayvee Villa";
JSONObject jo1 = new JSONObject();
for (int i = 0; i < innermost.length; i++)
jo1.put(innermost[i], values[i]);
JSONObject jo2 = new JSONObject();
for (int i = 0; i < inner.length; i++)
jo2.put(inner[i], jo1);
JSONObject jo3 = new JSONObject();
jo3.put(in, jo2);
String merger = jsonObj.toString().substring(0, jsonObj.toString().length()-1) + "," +jo3.toString().substring(1);
System.out.println(merger);
FileWriter pr = new FileWriter(file);
pr.write(merger);
pr.flush();
pr.close();
}
Merging typed data structure trees is not trivial, you need to define the precedence, handle incompatible types, define how they will be casted and merged...
So in my opinion, you won't avoid
... pulling them all apart and individually adding in by puts`.
If your question is: Has someone done it for me yet?
Then I think you can have a look at this YAML merging library/tool I revived. (YAML is a superset of JSON), and the principles are applicable to both.
(However, this particular code returns YAML objects, not JSON. Feel free to extend the project and send a PR.)
Today, I was also struggling to merge JSON objects and came with following solution (uses Gson library).
private JsonObject mergeJsons(List<JsonObject> jsonObjs) {
JsonObject mergedJson = new JsonObject();
jsonObjs.forEach((JsonObject jsonObj) -> {
Set<Map.Entry<String, JsonElement>> entrySet = jsonObj.entrySet();
entrySet.forEach((next) -> {
mergedJson.add(next.getKey(), next.getValue());
});
});
return mergedJson;
}
Somebody already mentioned above. I'll just post a short version.
To merge two JSONObject json1 & json2 You could simply deal it with String like this:
String merged = json1.toString().substring(0, json1.length() - 1) + "," +
json2.toString().substring(1);
JSONObject mergedJson = new JSONObject(merged);
Of course, do not forget deal with JSONException. :)
Hope this could help you.
An improved version of merge on Gson's JsonObjects - can go any level of nested structure
/**
* Merge "source" into "target".
*
* <pre>
* An improved version of merge on Gson's JsonObjects - can go any level of nested structure:
* 1. merge root & nested attributes.
* 2. replace list of strings. For. eg.
* source -> "listOfStrings": ["A!"]
* dest -> "listOfStrings": ["A", "B"]
* merged -> "listOfStrings": ["A!", "B"]
* 3. can merge nested objects inside list. For. eg.
* source -> "listOfObjects": [{"key2": "B"}]
* dest -> "listOfObjects": [{"key1": "A"}]
* merged -> "listOfObjects": [{"key1": "A"}, {"key2": "B"}]
* </pre>
* #return the merged object (target).
*/
public static JsonObject deepMerge(JsonObject source, JsonObject target) {
for (String key: source.keySet()) {
JsonElement srcValue = source.get(key);
if (!target.has(key)) {
target.add(key, srcValue);
} else {
if (srcValue instanceof JsonArray) {
JsonArray srcArray = (JsonArray)srcValue;
JsonArray destArray = target.getAsJsonArray(key);
if (destArray == null || destArray.size() == 0) {
target.add(key, srcArray);
continue;
} else {
IntStream.range(0, srcArray.size()).forEach(index -> {
JsonElement srcElem = srcArray.get(index);
JsonElement destElem = null;
if (index < destArray.size()) {
destElem = destArray.get(index);
}
if (srcElem instanceof JsonObject) {
if (destElem == null) {
destElem = new JsonObject();
}
deepMerge((JsonObject) srcElem, (JsonObject) destElem);
} else {
destArray.set(index, srcElem);
}
});
}
} else if (srcValue instanceof JsonObject) {
JsonObject valueJson = (JsonObject)srcValue;
deepMerge(valueJson, target.getAsJsonObject(key));
} else {
target.add(key, srcValue);
}
}
}
return target;
}
Here is a version of https://stackoverflow.com/a/15070484/9897317 including JSONArrays :
/**
* Merge "source" into "target". If fields have equal name, merge them recursively.
* #return the merged object (target).
*/
public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException {
for (String key: JSONObject.getNames(source)) {
Object value = source.get(key);
if (value != null) {
if (!target.has(key)) {
// new value for "key":
target.put(key, value);
} else {
// existing value for "key" - recursively deep merge:
if (value instanceof JSONObject) {
JSONObject valueJson = (JSONObject)value;
deepMerge(valueJson, target.getJSONObject(key));
} else if (value instanceof JSONArray) {
JSONArray arr = (JSONArray) value;
JSONArray newArr = new JSONArray();
for (int i = 0; i < arr.length(); i++) {
newArr.put(deepMerge(arr.getJSONObject(i), target.getJSONArray(key).getJSONObject(i)));
}
target.put(key, newArr);
} else {
target.put(key, value);
}
}
}
}
return target;
}