JOHNZON-304 Json.createDiff does not handle properly arrays overflow (more elements in target than source) + minor toString/cache values enhancements (useful for debug purposes)
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonArrayImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonArrayImpl.java
index 7f87069..d05cfbf 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonArrayImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonArrayImpl.java
@@ -163,6 +163,9 @@
@Override
public String toString() {
+ if (unmodifieableBackingList.isEmpty()) {
+ return "[]";
+ }
final StringWriter writer = new StringWriter();
try (final JsonGenerator generator = new JsonGeneratorImpl(writer, provider, false)) {
generator.writeStartArray();
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonObjectImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonObjectImpl.java
index 03d65fe..4e45f08 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonObjectImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonObjectImpl.java
@@ -143,6 +143,9 @@
@Override
public String toString() {
+ if (unmodifieableBackingMap.isEmpty()) {
+ return "{}";
+ }
final StringWriter writer = new StringWriter();
try (final JsonGenerator generator = new JsonGeneratorImpl(writer, provider, false)) {
generator.writeStartObject();
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchDiff.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchDiff.java
index 8610184..29577f0 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchDiff.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchDiff.java
@@ -61,19 +61,16 @@
private void diffJsonArray(JsonPatchBuilder patchBuilder, String basePath, JsonArray source, JsonArray target) {
for (int i = 0; i < source.size(); i++) {
- JsonValue sourceValue = source.get(i);
-
+ final JsonValue sourceValue = source.get(i);
if (target.size() <= i) {
patchBuilder.remove(basePath + i);
continue;
}
-
diff(patchBuilder, basePath + i, sourceValue, target.get(i));
}
if (target.size() > source.size()) {
-
- for (int i = target.size() - source.size(); i < target.size(); i++) {
+ for (int i = source.size(); i < target.size(); i++) {
patchBuilder.add(basePath + i, target.get(i));
}
}
@@ -81,8 +78,7 @@
}
private void diffJsonObjects(JsonPatchBuilder patchBuilder, String basePath, JsonObject source, JsonObject target) {
-
- for (Map.Entry<String, JsonValue> sourceEntry : source.entrySet()) {
+ for (final Map.Entry<String, JsonValue> sourceEntry : source.entrySet()) {
String attributeName = sourceEntry.getKey();
if (target.containsKey(attributeName)) {
@@ -93,13 +89,10 @@
}
}
- for (Map.Entry<String, JsonValue> targetEntry : target.entrySet()) {
+ for (final Map.Entry<String, JsonValue> targetEntry : target.entrySet()) {
if (!source.containsKey(targetEntry.getKey())) {
patchBuilder.add(basePath + JsonPointerUtil.encode(targetEntry.getKey()), targetEntry.getValue());
}
}
-
}
-
-
}
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java
index ec3109d..91bb436 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchImpl.java
@@ -38,6 +38,7 @@
private final JsonProvider provider;
private final List<PatchValue> patches;
+ private volatile JsonArray json;
JsonPatchImpl(final JsonProvider provider, final PatchValue... patches) {
this(provider, Arrays.asList(patches));
@@ -118,16 +119,30 @@
@Override
public JsonArray toJsonArray() {
-
- JsonArrayBuilder builder = provider.createArrayBuilder();
- for (PatchValue patch : patches) {
- builder.add(patch.toJson());
+ if (patches.isEmpty()) {
+ return JsonValue.EMPTY_JSON_ARRAY;
}
-
- return builder.build();
+ if (json == null) {
+ synchronized (this) {
+ if (json == null) {
+ final JsonArrayBuilder builder = provider.createArrayBuilder();
+ for (final PatchValue patch : patches) {
+ builder.add(patch.toJson());
+ }
+ json = builder.build();
+ }
+ }
+ }
+ return json;
}
-
+ @Override
+ public String toString() {
+ if (patches.isEmpty()) {
+ return "[]";
+ }
+ return toJsonArray().toString();
+ }
static class PatchValue {
private final JsonProvider provider;
@@ -136,6 +151,10 @@
private final JsonPointerImpl from;
private final JsonValue value;
+ private volatile String str;
+ private volatile JsonObject json;
+ private volatile Integer hash;
+
PatchValue(final JsonProvider provider,
final JsonPatch.Operation operation,
final String path,
@@ -181,38 +200,54 @@
@Override
public int hashCode() {
- int result = operation.hashCode();
- result = 31 * result + path.hashCode();
- result = 31 * result + (from != null ? from.hashCode() : 0);
- result = 31 * result + (value != null ? value.hashCode() : 0);
- return result;
+ if (hash == null) {
+ synchronized (this) {
+ if (hash == null) {
+ int result = operation.hashCode();
+ result = 31 * result + path.hashCode();
+ result = 31 * result + (from != null ? from.hashCode() : 0);
+ result = 31 * result + (value != null ? value.hashCode() : 0);
+ hash = result;
+ }
+ }
+ }
+ return hash;
}
@Override
public String toString() {
- return "{" +
- "op: " + operation +
- ", path: " + path +
- ", from: " + from +
- ", value: " + value +
- '}';
+ if (str == null) {
+ synchronized (this) {
+ if (str == null) {
+ str = "{op: " + operation + ", path: " + path + ", from: " + from + ", value: " + value + '}';
+ }
+ }
+ }
+ return str;
}
JsonObject toJson() {
- JsonObjectBuilder builder = provider.createObjectBuilder()
- .add("op", operation.name().toLowerCase())
- .add("path", path.getJsonPointer());
+ if (json == null) {
+ synchronized (this) {
+ if (json == null) {
+ JsonObjectBuilder builder = provider.createObjectBuilder()
+ .add("op", operation.name().toLowerCase())
+ .add("path", path.getJsonPointer());
- if (from != null) {
- builder.add("from", from.getJsonPointer());
+ if (from != null) {
+ builder.add("from", from.getJsonPointer());
+ }
+
+ if (value != null) {
+ builder.add("value", value);
+ }
+
+ json = builder.build();
+ }
+ }
}
-
- if (value != null) {
- builder.add("value", value);
- }
-
- return builder.build();
+ return json;
}
}
}
diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchDiffTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchDiffTest.java
index 51bada2..d591b98 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchDiffTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonPatchDiffTest.java
@@ -32,6 +32,25 @@
import org.junit.Test;
public class JsonPatchDiffTest {
+ @Test
+ public void fromEmptyArray() {
+ final JsonObject from = Json.createObjectBuilder().add("testEmpty", JsonValue.EMPTY_JSON_ARRAY).build();
+ final JsonObject to = Json.createObjectBuilder()
+ .add("testEmpty", Json.createArrayBuilder().add("something"))
+ .build();
+ final JsonPatch diff = Json.createDiff(from, to);
+ assertEquals("[{\"op\":\"add\",\"path\":\"/testEmpty/0\",\"value\":\"something\"}]", diff.toString());
+ }
+
+ @Test
+ public void toEmptyArray() {
+ final JsonObject from = Json.createObjectBuilder()
+ .add("testEmpty", Json.createArrayBuilder().add("something"))
+ .build();
+ final JsonObject to = Json.createObjectBuilder().add("testEmpty", JsonValue.EMPTY_JSON_ARRAY).build();
+ final JsonPatch diff = Json.createDiff(from, to);
+ assertEquals("[{\"op\":\"remove\",\"path\":\"/testEmpty/0\"}]", diff.toString());
+ }
@Test
public void testAddDiff() {