diff --git a/README.md b/README.md index 6ca36f0..dc36e98 100644 --- a/README.md +++ b/README.md @@ -165,10 +165,11 @@ jsonObject.set("quantity", 24); jsonObject.remove("quantity"); ``` -`JsonObject` also provides a `merge` method that copies all members from a given JSON object. +`JsonObject` also provides a `merge` and a `deepMerge` method that copies all members from a given JSON object. ```java jsonObject.merge(otherObject); +jsonObject.deepMerge(otherObject); // merges common object members recursively ``` ### Output JSON diff --git a/com.eclipsesource.json/src/main/java/com/eclipsesource/json/JsonObject.java b/com.eclipsesource.json/src/main/java/com/eclipsesource/json/JsonObject.java index cb05833..a0b2796 100644 --- a/com.eclipsesource.json/src/main/java/com/eclipsesource/json/JsonObject.java +++ b/com.eclipsesource.json/src/main/java/com/eclipsesource/json/JsonObject.java @@ -557,6 +557,34 @@ public JsonObject merge(JsonObject object) { return this; } + /** + * Copies all members of the specified object into this object. When the specified object contains + * members with names that also exist in this object, the existing values in this object will be + * replaced by the corresponding values in the specified object, except for the case that both values + * are JsonObjects themselves, which will trigger another merge of these objects + * + * @param object + * the object to merge + * @return the object itself, to enable method chaining + */ + public JsonObject deepMerge(JsonObject object) { + if (object == null) { + throw new NullPointerException("object is null"); + } + for (Member member : object) { + final String name = member.name; + JsonValue value = member.value; + if (value instanceof JsonObject) { + final JsonValue existingValue = this.get(member.name); + if (existingValue instanceof JsonObject) { + value = ((JsonObject) existingValue).deepMerge((JsonObject) value); + } + } + this.set(name, value); + } + return this; + } + /** * Returns the value of the member with the specified name in this object. If this object contains * multiple members with the given name, this method will return the last one. diff --git a/com.eclipsesource.json/src/test/java/com/eclipsesource/json/JsonObject_Test.java b/com.eclipsesource.json/src/test/java/com/eclipsesource/json/JsonObject_Test.java index 76f7091..7f34b4b 100644 --- a/com.eclipsesource.json/src/test/java/com/eclipsesource/json/JsonObject_Test.java +++ b/com.eclipsesource.json/src/test/java/com/eclipsesource/json/JsonObject_Test.java @@ -768,6 +768,41 @@ public void merge_replacesMembers() { assertEquals(Json.object().add("a", 1).add("b", 2).add("c", 1).add("d", 2), object); } + @Test + public void deepMerge_failsWithNull() { + assertException(NullPointerException.class, "object is null", new Runnable() { + public void run() { + object.deepMerge(null); + } + }); + } + + @Test + public void deepMerge_appendsMembers() { + object.add("a", 1).add("b", 1); + object.deepMerge(Json.object().add("c", 2).add("d", 2)); + + assertEquals(Json.object().add("a", 1).add("b", 1).add("c", 2).add("d", 2), object); + } + + @Test + public void deepMerge_replacesMembers() { + object.add("a", 1).add("b", 1).add("c", 1); + object.deepMerge(Json.object().add("b", 2).add("d", 2)); + + assertEquals(Json.object().add("a", 1).add("b", 2).add("c", 1).add("d", 2), object); + } + + @Test + public void deepMerge_mergesMemberObject() { + object.add("a", 1).add("b", Json.object().add("x", 1).add("y", 1)).add("c", Json.object().add("A", 1)); + object.deepMerge(Json.object().add("b", Json.object().add("y", 2).add("z", 1)).add("c", 1) + .add("d", Json.object().add("B", 1))); + + assertEquals(Json.object().add("a", 1).add("b", Json.object().add("x", 1).add("y", 2).add("z", 1)).add("c", 1) + .add("d", Json.object().add("B", 1)), object); + } + @Test public void write_empty() throws IOException { JsonWriter writer = mock(JsonWriter.class);