Repository: johnzon Updated Branches: refs/heads/master 66ee778e8 -> 174ffa5ba
JOHNZON-103 add createMergeDiff handling Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/174ffa5b Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/174ffa5b Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/174ffa5b Branch: refs/heads/master Commit: 174ffa5babf73356af9a273fc7991e7567118102 Parents: 66ee778 Author: Mark Struberg <[email protected]> Authored: Wed Mar 8 14:08:49 2017 +0100 Committer: Mark Struberg <[email protected]> Committed: Wed Mar 8 14:08:49 2017 +0100 ---------------------------------------------------------------------- .../java/org/apache/johnzon/core/DiffBase.java | 34 ++++++++ .../apache/johnzon/core/JsonMergePatchDiff.java | 81 ++++++++++++++++++++ .../apache/johnzon/core/JsonMergePatchImpl.java | 5 -- .../org/apache/johnzon/core/JsonPatchDiff.java | 21 +---- .../apache/johnzon/core/JsonProviderImpl.java | 4 + .../johnzon/core/JsonMergeBatchDiffTest.java | 51 ++++++++++++ 6 files changed, 173 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/174ffa5b/johnzon-core/src/main/java/org/apache/johnzon/core/DiffBase.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/DiffBase.java b/johnzon-core/src/main/java/org/apache/johnzon/core/DiffBase.java new file mode 100644 index 0000000..d6abfdf --- /dev/null +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/DiffBase.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.johnzon.core; + +import javax.json.JsonArray; +import javax.json.JsonObject; +import javax.json.JsonValue; + +/** + * Commonly used methods for diffs + */ +class DiffBase { + protected boolean isJsonObject(JsonValue jsonValue) { + return jsonValue instanceof JsonObject; + } + + protected boolean isJsonArray(JsonValue targetValue) { + return targetValue instanceof JsonArray; + } +} http://git-wip-us.apache.org/repos/asf/johnzon/blob/174ffa5b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchDiff.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchDiff.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchDiff.java new file mode 100644 index 0000000..5175e8d --- /dev/null +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchDiff.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.johnzon.core; + +import java.util.Map; + +import javax.json.JsonMergePatch; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; + +/** + * Creates a JsonMergePatch as diff between two JsonValues + */ +class JsonMergePatchDiff extends DiffBase { + private final JsonValue source; + private final JsonValue target; + + public JsonMergePatchDiff(JsonValue source, JsonValue target) { + this.source = source; + this.target = target; + } + + public JsonMergePatch calculateDiff() { + return new JsonMergePatchImpl(diff(source, target)); + } + + private JsonValue diff(JsonValue source, JsonValue target) { + JsonObjectBuilder builder = new JsonObjectBuilderImpl(); + + if (isJsonObject(source) && isJsonObject(target)) { + JsonObject srcObj = source.asJsonObject(); + JsonObject targetObj = target.asJsonObject(); + for (Map.Entry<String, JsonValue> sourceEntry : srcObj.entrySet()) { + String attributeName = sourceEntry.getKey(); + if (targetObj.containsKey(attributeName)) { + // compare the attribute values + JsonValue attribDiff = diff(sourceEntry.getValue(), targetObj.get(attributeName)); + if (!JsonValue.EMPTY_JSON_OBJECT.equals(attribDiff)) { + builder.add(attributeName, attribDiff); + } + } else { + // attribute got removed + builder.add(attributeName, JsonValue.NULL); + } + } + + for (Map.Entry<String, JsonValue> targetEntry : targetObj.entrySet()) { + String attributeName = targetEntry.getKey(); + if (!srcObj.containsKey(attributeName)) { + // add operation + builder.add(attributeName, targetEntry.getValue()); + } + } + + return builder.build(); + } else if (source.equals(target)) { + // if the two objects are identical, then return an empty patch + return JsonValue.EMPTY_JSON_OBJECT; + } else { + // as defined in the RFC anything else than comparing JsonObjects will result + // in completely replacing the source with the target + // That means our target is the patch. + return target; + } + } +} http://git-wip-us.apache.org/repos/asf/johnzon/blob/174ffa5b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchImpl.java index a28c3d2..b3f55c6 100644 --- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchImpl.java +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchImpl.java @@ -19,7 +19,6 @@ package org.apache.johnzon.core; import java.util.Map; -import javax.json.JsonArray; import javax.json.JsonMergePatch; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; @@ -43,10 +42,6 @@ public class JsonMergePatchImpl implements JsonMergePatch { private JsonValue applyPatch(JsonValue valueToApplyPatchOn, JsonValue patch) { if (patch == null) { return JsonValue.NULL; - } else if (patch instanceof JsonArray) { - JsonArray patchArray = patch.asJsonArray(); - //X TODO - throw new UnsupportedOperationException("not yet implemented TODO finish JsonArray support."); } else if (patch instanceof JsonObject && valueToApplyPatchOn instanceof JsonObject) { // we only apply an actual patch IF both sides are a JsonObject JsonObject patchObject = patch.asJsonObject(); http://git-wip-us.apache.org/repos/asf/johnzon/blob/174ffa5b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonPatchDiff.java ---------------------------------------------------------------------- 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 bab7bd1..301a775 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 @@ -17,7 +17,6 @@ package org.apache.johnzon.core; import java.util.Map; -import java.util.Set; import javax.json.JsonArray; import javax.json.JsonObject; @@ -29,7 +28,7 @@ import javax.json.JsonValue; /** * Create a diff from a source and target JsonStructure */ -class JsonPatchDiff { +class JsonPatchDiff extends DiffBase { private final JsonStructure source; private final JsonStructure target; @@ -48,7 +47,6 @@ class JsonPatchDiff { } private void diff(JsonPatchBuilder patchBuilder, String basePath, JsonValue source, JsonValue target) { - if (isJsonObject(source) && isJsonObject(target)) { diffJsonObjects(patchBuilder, basePath + "/", (JsonObject) source, (JsonObject) target); } else if (isJsonArray(source) && isJsonArray(target)) { @@ -59,9 +57,7 @@ class JsonPatchDiff { } private void diffJsonArray(JsonPatchBuilder patchBuilder, String basePath, JsonArray source, JsonArray target) { - for (int i = 0; i < source.size(); i++) { - JsonValue sourceValue = source.get(i); if (target.size() <= i) { @@ -82,10 +78,8 @@ class JsonPatchDiff { } private void diffJsonObjects(JsonPatchBuilder patchBuilder, String basePath, JsonObject source, JsonObject target) { - Set<Map.Entry<String, JsonValue>> sourceEntries = source.entrySet(); - - for (Map.Entry<String, JsonValue> sourceEntry : sourceEntries) { + for (Map.Entry<String, JsonValue> sourceEntry : source.entrySet()) { String attributeName = sourceEntry.getKey(); if (target.containsKey(attributeName)) { @@ -96,8 +90,7 @@ class JsonPatchDiff { } } - Set<Map.Entry<String, JsonValue>> targetEntries = target.entrySet(); - for (Map.Entry<String, JsonValue> targetEntry : targetEntries) { + for (Map.Entry<String, JsonValue> targetEntry : target.entrySet()) { if (!source.containsKey(targetEntry.getKey())) { patchBuilder.add(basePath + JsonPointerUtil.encode(targetEntry.getKey()), targetEntry.getValue()); } @@ -106,12 +99,4 @@ class JsonPatchDiff { } - private static boolean isJsonObject(JsonValue jsonValue) { - return jsonValue instanceof JsonObject; - } - - private static boolean isJsonArray(JsonValue targetValue) { - return targetValue instanceof JsonArray; - } - } http://git-wip-us.apache.org/repos/asf/johnzon/blob/174ffa5b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java index a5d0c39..909d0ba 100644 --- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonProviderImpl.java @@ -373,5 +373,9 @@ public class JsonProviderImpl extends JsonProvider implements Serializable { return new JsonMergePatchImpl(patch); } + @Override + public JsonMergePatch createMergeDiff(JsonValue source, JsonValue target) { + return new JsonMergePatchDiff(source, target).calculateDiff(); + } } } http://git-wip-us.apache.org/repos/asf/johnzon/blob/174ffa5b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchDiffTest.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchDiffTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchDiffTest.java new file mode 100644 index 0000000..a2c7c3b --- /dev/null +++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchDiffTest.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.johnzon.core; + +import java.io.StringReader; + +import javax.json.Json; +import javax.json.JsonMergePatch; +import javax.json.JsonObject; + +import org.junit.Assert; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class JsonMergeBatchDiffTest { + + @Test + public void testAddDiff() { + // {"a":"xa"} + String jsonA = "{\"a\":\"xa\"}"; + + // {"a":"xa","b":"xb"} + String jsonB = "{\"a\":\"xa\",\"b\":\"xb\"}"; + + // this results in 1 diff operations: + // adding "b" + JsonMergePatch jsonMergePatch = Json.createMergeDiff(Json.createReader(new StringReader(jsonA)).readObject(), + Json.createReader(new StringReader(jsonB)).readObject()); + assertNotNull(jsonMergePatch); + JsonObject patchJson = jsonMergePatch.toJsonValue().asJsonObject(); + assertNotNull(patchJson); + assertEquals(1, patchJson.entrySet().size()); + Assert.assertEquals("xb", patchJson.getString("b")); + } + +}
