Repository: johnzon Updated Branches: refs/heads/master e2905f9ec -> ea31ad7d2
JOHNZON-96 implement JsonMergePatch Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/ea31ad7d Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/ea31ad7d Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/ea31ad7d Branch: refs/heads/master Commit: ea31ad7d204d27221b89d268c4f89a93ebec41ef Parents: e2905f9 Author: Mark Struberg <[email protected]> Authored: Tue Mar 7 22:52:23 2017 +0100 Committer: Mark Struberg <[email protected]> Committed: Tue Mar 7 22:52:43 2017 +0100 ---------------------------------------------------------------------- .../johnzon/core/JsonMergePatchBuilder.java | 2 +- .../apache/johnzon/core/JsonMergePatchImpl.java | 85 ++++++++++++++++++++ .../apache/johnzon/core/JsonProviderImpl.java | 4 + .../apache/johnzon/core/JsonMergeBatchTest.java | 56 ++++++++++--- 4 files changed, 136 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/ea31ad7d/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchBuilder.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchBuilder.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchBuilder.java index 831e82e..2c56a13 100644 --- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchBuilder.java +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchBuilder.java @@ -19,7 +19,7 @@ package org.apache.johnzon.core; import javax.json.JsonValue; /** - * Creates and applies a Json Merge Patch as defined in + * Creates a JsonPatchBuilder which will create {@link javax.json.JsonMergePatch} as defined in * https://tools.ietf.org/html/rfc7396 */ public class JsonMergePatchBuilder { http://git-wip-us.apache.org/repos/asf/johnzon/blob/ea31ad7d/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 new file mode 100644 index 0000000..a28c3d2 --- /dev/null +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonMergePatchImpl.java @@ -0,0 +1,85 @@ +/* + * 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.JsonArray; +import javax.json.JsonMergePatch; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; + +/** + * @author <a href="mailto:[email protected]">Mark Struberg</a> + */ +public class JsonMergePatchImpl implements JsonMergePatch { + private final JsonValue patch; + + public JsonMergePatchImpl(JsonValue patch) { + this.patch = patch; + } + + @Override + public JsonValue apply(JsonValue valueToApplyPatchOn) { + return applyPatch(valueToApplyPatchOn, patch); + } + + 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(); + + return applyJsonObjectPatch(valueToApplyPatchOn.asJsonObject(), patchObject); + } else { + // this must be a native JsonValue or JsonObject, so we just replace the + // the whole original valueToApplyPatchOn with the new jsonValue + return patch; + } + } + + private JsonValue applyJsonObjectPatch(JsonObject jsonObject, JsonObject patch) { + JsonObjectBuilder builder = new JsonObjectBuilderImpl(jsonObject); + + for (Map.Entry<String, JsonValue> patchAttrib : patch.entrySet()) { + String attribName = patchAttrib.getKey(); + if (patchAttrib.getValue().equals(JsonValue.NULL)) { + builder.remove(attribName); + } else { + JsonValue originalAttrib = jsonObject.get(attribName); + if (originalAttrib == null) { + builder.add(attribName, patchAttrib.getValue()); + } else { + builder.add(attribName, applyPatch(originalAttrib, patchAttrib.getValue())); + } + } + } + return builder.build(); + } + + @Override + public JsonValue toJsonValue() { + return patch; + } +} http://git-wip-us.apache.org/repos/asf/johnzon/blob/ea31ad7d/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 c7c8000..190ba05 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 @@ -369,6 +369,10 @@ public class JsonProviderImpl extends JsonProvider implements Serializable { return new JsonPatchDiff(source, target).calculateDiff(); } + public JsonMergePatch createMergePatch(JsonValue patch) { + return new JsonMergePatchImpl(patch); + } + //X TODO add missing methods } http://git-wip-us.apache.org/repos/asf/johnzon/blob/ea31ad7d/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchTest.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchTest.java index ff4c078..172921b 100644 --- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchTest.java +++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonMergeBatchTest.java @@ -21,35 +21,71 @@ import java.io.StringReader; import javax.json.Json; import javax.json.JsonMergePatch; +import javax.json.JsonNumber; import javax.json.JsonObject; +import javax.json.JsonValue; +import javax.json.spi.JsonProvider; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; public class JsonMergeBatchTest { + private JsonProvider json = JsonProvider.provider(); + @Test - @Ignore(value = "work in progress, TODO finish") - public void testSimpleMergePatch() { - // {"a":"xa","b","xb"} - String source = "{\"a\":\"xa\",\"b\",\"xb\"}"; + public void testApplyValueOnObject() { + // {"a":"xa","b":"xb"} + JsonObject source = jsonObjectFrom("{\"a\":\"xa\",\"b\":\"xb\"}"); // {"b":"bNew","c":"xc"} // the result after this patch gets applied to source should be {"a":"xa","b","bNew","c":"xc"} - String patch = "{\"b\":\"bNew\",\"c\":\"xc\"}"; + JsonValue patch = json.createValue(4711); + + JsonMergePatch jsonMergePatch = Json.createMergePatch(patch); + JsonValue patchedValue = jsonMergePatch.apply(source); + Assert.assertEquals(4711, ((JsonNumber) patchedValue).intValue()); + } + + @Test + public void testApplyObjectOnValue() { + // {"a":"xa","b":"xb"} + JsonValue source = json.createValue(4711); + + // {"b":"bNew","c":"xc"} + // the result after this patch gets applied to source should be {"a":"xa","b","bNew","c":"xc"} + JsonObject patch = jsonObjectFrom("{\"a\":\"xa\",\"b\":\"xb\"}"); + + JsonMergePatch jsonMergePatch = Json.createMergePatch(patch); + JsonValue patchedValue = jsonMergePatch.apply(source); + Assert.assertTrue(patchedValue instanceof JsonObject); + Assert.assertEquals("xa", patchedValue.asJsonObject().getString("a")); + Assert.assertEquals("xb", patchedValue.asJsonObject().getString("b")); + } + - //X TODO Json.createMergePatch(); + @Test + public void testSimpleJsonObjectMergePatch() { + // {"a":"xa","b":"xb"} + JsonObject source = jsonObjectFrom("{\"a\":\"xa\",\"b\":\"xb\"}"); - JsonMergePatch jsonMergePatch = Json.createMergePatch(Json.createReader(new StringReader(patch)).readObject()); + // {"b":"bNew","c":"xc"} + // the result after this patch gets applied to source should be {"a":"xa","b","bNew","c":"xc"} + JsonObject patch = jsonObjectFrom("{\"b\":\"bNew\",\"c\":\"xc\"}"); - JsonObject jsonSource = Json.createReader(new StringReader(source)).readObject(); + JsonMergePatch jsonMergePatch = Json.createMergePatch(patch); - JsonObject jsonTarget = jsonMergePatch.apply(jsonSource).asJsonObject(); + + JsonObject jsonTarget = jsonMergePatch.apply(source).asJsonObject(); Assert.assertNotNull(jsonTarget); Assert.assertEquals(3, jsonTarget.entrySet().size()); Assert.assertEquals("xa", jsonTarget.getString("a")); Assert.assertEquals("bNew", jsonTarget.getString("b")); Assert.assertEquals("xc", jsonTarget.getString("c")); } + + + private JsonObject jsonObjectFrom(String val) { + return json.createReader(new StringReader(val)).readObject(); + } }
