Skip to content

fix JSONObject.merge blocks overwriting (#175) #238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions json-smart/src/main/java/net/minidev/json/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,18 +197,27 @@ public void writeJSONString(Appendable out, JSONStyle compression) throws IOExce
}

public void merge(Object o2) {
merge(this, o2);
merge(this, o2, false);
}

protected static JSONObject merge(JSONObject o1, Object o2) {
/**
* merge two JSONObject with overwrite or not
* overwrite = false will not overwrite existing key
* overwrite = true will overwrite the value with o2 of existing key
*/
public void merge(Object o2, boolean overwrite) {
merge(this, o2, overwrite);
}

protected static JSONObject merge(JSONObject o1, Object o2, boolean overwrite) {
if (o2 == null)
return o1;
if (o2 instanceof JSONObject)
return merge(o1, (JSONObject) o2);
return merge(o1, (JSONObject) o2, overwrite);
throw new RuntimeException("JSON merge can not merge JSONObject with " + o2.getClass());
}

private static JSONObject merge(JSONObject o1, JSONObject o2) {
private static JSONObject merge(JSONObject o1, JSONObject o2, boolean overwrite) {
if (o2 == null)
return o1;
for (String key : o1.keySet()) {
Expand All @@ -221,13 +230,18 @@ private static JSONObject merge(JSONObject o1, JSONObject o2) {
continue;
}
if (value1 instanceof JSONObject) {
o1.put(key, merge((JSONObject) value1, value2));
o1.put(key, merge((JSONObject) value1, value2, overwrite));
continue;
}
if (value1.equals(value2))
continue;
if (value1.getClass() .equals(value2.getClass()))
if (value1.getClass().equals(value2.getClass())) {
if (overwrite) {
o1.put(key, value2);
continue;
}
throw new RuntimeException("JSON merge can not merge two " + value1.getClass().getName() + " Object together");
}
throw new RuntimeException("JSON merge can not merge " + value1.getClass().getName() + " with " + value2.getClass().getName());
}
for (String key : o2.keySet()) {
Expand Down
178 changes: 178 additions & 0 deletions json-smart/src/test/java/net/minidev/json/test/JSONObjectTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package net.minidev.json.test;

import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class JSONObjectTest {

@Test
void mergeIntegerFailed() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", 1);
Assertions.assertEquals("{\"k1\":1}", jsonObject1.toJSONString());

// replace with new value by Map merge
jsonObject1.merge("k1", 11, (oldValue, newValue) -> newValue);
Assertions.assertEquals("{\"k1\":11}", jsonObject1.toJSONString());

JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k2", 2);
jsonObject1.merge(jsonObject3);
Assertions.assertEquals("{\"k1\":11,\"k2\":2}", jsonObject1.toJSONString());

// replace with new value by JSONObject merge will fail
Exception exception = Assertions.assertThrows(RuntimeException.class, () -> {
JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k1", 101);
jsonObject1.merge(jsonObject2);
});

Assertions.assertEquals(exception.getMessage(), "JSON merge can not merge two java.lang.Integer Object together");
}

@Test
void mergeStringFailed() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", "v1");
Assertions.assertEquals("{\"k1\":\"v1\"}", jsonObject1.toJSONString());

// replace with new value by Map merge
jsonObject1.merge("k1", "vNew1", (oldValue, newValue) -> newValue);
Assertions.assertEquals("{\"k1\":\"vNew1\"}", jsonObject1.toJSONString());

JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k2", "v2");
jsonObject1.merge(jsonObject3);
Assertions.assertEquals("{\"k1\":\"vNew1\",\"k2\":\"v2\"}", jsonObject1.toJSONString());

// replace with new value by JSONObject merge will fail
Exception exception = Assertions.assertThrows(RuntimeException.class, () -> {
JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k1", "vNew2");
jsonObject1.merge(jsonObject2);
System.out.println(jsonObject1.toJSONString());
});

Assertions.assertEquals(exception.getMessage(), "JSON merge can not merge two java.lang.String Object together");
}

@Test
void mergeJsonObjectFailed() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", "v1");
Assertions.assertEquals("{\"k1\":\"v1\"}", jsonObject1.toJSONString());

JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k2", jsonObject1);
Assertions.assertEquals("{\"k2\":{\"k1\":\"v1\"}}", jsonObject2.toJSONString());

// replace with new value by JSONObject merge will fail
JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k1", "vNew1");

JSONObject jsonObject4 = new JSONObject();
jsonObject4.appendField("k2", jsonObject3);
Assertions.assertEquals("{\"k2\":{\"k1\":\"vNew1\"}}", jsonObject4.toJSONString());

Exception exception = Assertions.assertThrows(RuntimeException.class, () -> {
jsonObject4.merge(jsonObject2);
});

Assertions.assertEquals(exception.getMessage(), "JSON merge can not merge two java.lang.String Object together");
}

@Test
void mergeJsonArraySuccess() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", "v1");
JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k2", "v2");

JSONArray jsonArray1 = new JSONArray();
jsonArray1.add(jsonObject1);
jsonArray1.add(jsonObject2);
Assertions.assertEquals("[{\"k1\":\"v1\"},{\"k2\":\"v2\"}]", jsonArray1.toJSONString());

// replace with new value by JSONObject merge will fail
JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k1", "vNew1");
JSONObject jsonObject4 = new JSONObject();
jsonObject4.appendField("k2", "vNew2");

JSONArray jsonArray2 = new JSONArray();
jsonArray2.add(jsonObject3);
jsonArray2.add(jsonObject4);
Assertions.assertEquals("[{\"k1\":\"vNew1\"},{\"k2\":\"vNew2\"}]", jsonArray2.toJSONString());

jsonArray2.merge(jsonArray1);
Assertions.assertEquals("[{\"k1\":\"vNew1\"},{\"k2\":\"vNew2\"},{\"k1\":\"v1\"},{\"k2\":\"v2\"}]", jsonArray2.toJSONString());
}

@Test
void mergeIntegerWithOverwriteSuccess() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", 1);
Assertions.assertEquals("{\"k1\":1}", jsonObject1.toJSONString());

// replace with new value by Map merge
jsonObject1.merge("k1", 11, (oldValue, newValue) -> newValue);
Assertions.assertEquals("{\"k1\":11}", jsonObject1.toJSONString());

JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k2", 2);
jsonObject1.merge(jsonObject3);
Assertions.assertEquals("{\"k1\":11,\"k2\":2}", jsonObject1.toJSONString());

// replace with new value by JSONObject merge with override success
JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k1", 101);
jsonObject1.merge(jsonObject2, true);
Assertions.assertEquals("{\"k1\":101,\"k2\":2}", jsonObject1.toJSONString());
}

@Test
void mergeStringWithOverwriteSuccess() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", "v1");
Assertions.assertEquals("{\"k1\":\"v1\"}", jsonObject1.toJSONString());

// replace with new value by Map merge
jsonObject1.merge("k1", "vNew1", (oldValue, newValue) -> newValue);
Assertions.assertEquals("{\"k1\":\"vNew1\"}", jsonObject1.toJSONString());

JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k2", "v2");
jsonObject1.merge(jsonObject3);
Assertions.assertEquals("{\"k1\":\"vNew1\",\"k2\":\"v2\"}", jsonObject1.toJSONString());

// replace with new value by JSONObject merge with override success
JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k1", "vNew2");
jsonObject1.merge(jsonObject2, true);
Assertions.assertEquals("{\"k1\":\"vNew2\",\"k2\":\"v2\"}", jsonObject1.toJSONString());
}

@Test
void mergeJsonObjectWithOverwriteSuccess() {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.appendField("k1", "v1");
Assertions.assertEquals("{\"k1\":\"v1\"}", jsonObject1.toJSONString());

JSONObject jsonObject2 = new JSONObject();
jsonObject2.appendField("k2", jsonObject1);
Assertions.assertEquals("{\"k2\":{\"k1\":\"v1\"}}", jsonObject2.toJSONString());

// JSONObject merge will overwrite jsonObject3 by jsonObject2
JSONObject jsonObject3 = new JSONObject();
jsonObject3.appendField("k1", "vNew1");

JSONObject jsonObject4 = new JSONObject();
jsonObject4.appendField("k2", jsonObject3);
Assertions.assertEquals("{\"k2\":{\"k1\":\"vNew1\"}}", jsonObject4.toJSONString());

jsonObject4.merge(jsonObject2, true);
Assertions.assertEquals("{\"k2\":{\"k1\":\"v1\"}}", jsonObject4.toJSONString());
}
}