This is an automated email from the ASF dual-hosted git repository. rmannibucau pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/johnzon.git
The following commit(s) were added to refs/heads/master by this push: new a602490 [JOHNZON-336] jsonpatch operators for jsonlogic a602490 is described below commit a6024900b68c14e86742dd231ba318d20a18a975 Author: Romain Manni-Bucau <rmannibu...@gmail.com> AuthorDate: Wed Feb 17 10:01:22 2021 +0100 [JOHNZON-336] jsonpatch operators for jsonlogic --- .../apache/johnzon/jsonlogic/JohnzonJsonLogic.java | 49 +++++++++++++- .../johnzon/jsonlogic/JohnzonJsonLogicTest.java | 74 ++++++++++++++++++++++ src/site/markdown/index.md | 2 + 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java index 9691c82..21e7618 100644 --- a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java +++ b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogic.java @@ -24,8 +24,10 @@ import javax.json.JsonArray; import javax.json.JsonArrayBuilder; import javax.json.JsonBuilderFactory; import javax.json.JsonException; +import javax.json.JsonMergePatch; import javax.json.JsonNumber; import javax.json.JsonObject; +import javax.json.JsonPatch; import javax.json.JsonPointer; import javax.json.JsonString; import javax.json.JsonStructure; @@ -37,6 +39,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiPredicate; import java.util.stream.Collector; import java.util.stream.DoubleStream; @@ -49,13 +52,18 @@ import static java.util.stream.Collectors.joining; public class JohnzonJsonLogic { private final JsonProvider provider; private final Map<String, Operator> operators = new HashMap<>(); - private final Map<String, JsonPointer> pointers = new HashMap<>(); + private final Map<String, JsonPointer> pointers = new ConcurrentHashMap<>(); + private final Map<JsonArray, JsonPatch> jsonPatches = new ConcurrentHashMap<>(); + private final Map<JsonValue, JsonMergePatch> jsonMergePatches = new ConcurrentHashMap<>(); private final JsonBuilderFactory builderFactory; private boolean cachePointers; + private boolean cacheJsonPatches; + private boolean cacheJsonMergePatches; public JohnzonJsonLogic() { this(JsonProvider.provider()); registerDefaultOperators(); + registerExtensionsOperators(); } public JohnzonJsonLogic(final JsonProvider provider) { @@ -68,6 +76,16 @@ public class JohnzonJsonLogic { return this; } + public JohnzonJsonLogic cacheJsonPatches() { + this.cacheJsonPatches = true; + return this; + } + + public JohnzonJsonLogic cacheJsonMergePatches() { + this.cacheJsonMergePatches = true; + return this; + } + public JohnzonJsonLogic registerOperator(final String name, final Operator impl) { operators.put(name, impl); return this; @@ -190,6 +208,35 @@ public class JohnzonJsonLogic { } } + public JohnzonJsonLogic registerExtensionsOperators() { + registerOperator("jsonpatch", (logic, config, params) -> getJsonPatch(config) + .apply(JsonStructure.class.cast(params))); + registerOperator("jsonmergepatch", (logic, config, params) -> getJsonMergePatch(config) + .apply(params)); + registerOperator("jsonmergediff", (logic, config, params) -> { + final JsonArray array = params.asJsonArray(); + if (array.size() != 2) { + throw new IllegalArgumentException("jsonmergediff should have 2 parameters (in an array): " + array); + } + return provider.createMergeDiff(config, array.get(0)).apply(array.get(1)); + }); + return this; + } + + private JsonPatch getJsonPatch(final JsonValue config) { + if (!cacheJsonPatches) { + return provider.createPatch(config.asJsonArray()); + } + return jsonPatches.computeIfAbsent(config.asJsonArray(), provider::createPatch); + } + + private JsonMergePatch getJsonMergePatch(final JsonValue config) { + if (!cacheJsonPatches) { + return provider.createMergePatch(config); + } + return jsonMergePatches.computeIfAbsent(config, provider::createMergePatch); + } + // to not depend on a logger we don't register "log" operation but it is trivial to do: public JohnzonJsonLogic registerDefaultOperators() { registerOperator("log", (logic, config, params) -> { diff --git a/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java b/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java index f126cfd..53950ab 100644 --- a/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java +++ b/johnzon-jsonlogic/src/test/java/org/apache/johnzon/jsonlogic/JohnzonJsonLogicTest.java @@ -25,6 +25,7 @@ import org.junit.Test; import javax.json.Json; import javax.json.JsonBuilderFactory; import javax.json.JsonObject; +import javax.json.JsonPatch; import javax.json.JsonValue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -123,6 +124,79 @@ public class JohnzonJsonLogicTest { } @Test + public void jsonPatch() { + assertEquals( + builderFactory.createObjectBuilder() + .add("dummy", builderFactory.createObjectBuilder().add("added", true)) + .add("foo", "replaced") + .build(), + jsonLogic.apply( + builderFactory.createObjectBuilder() + .add("jsonpatch", builderFactory.createArrayBuilder() + .add(builderFactory.createObjectBuilder() + .add("op", JsonPatch.Operation.ADD.operationName()) + .add("path", "/dummy") + .add("value", builderFactory.createObjectBuilder() + .add("added", true))) + .add(builderFactory.createObjectBuilder() + .add("op", JsonPatch.Operation.REPLACE.operationName()) + .add("path", "/foo") + .add("value", "replaced"))) + .build(), + Json.createObjectBuilder().add("foo", "bar").build())); + } + + @Test + public void jsonMergePatch() { + assertEquals( + builderFactory.createObjectBuilder() + .add("a", "z") + .add("c", builderFactory.createObjectBuilder() + .add("d", "e")) + .build(), + jsonLogic.apply( + builderFactory.createObjectBuilder() + .add("jsonmergepatch", builderFactory.createObjectBuilder() + .add("a", "z") + .add("c", builderFactory.createObjectBuilder() + .addNull("f")) + .build()) + .build(), + builderFactory.createObjectBuilder() + .add("a", "b") + .add("c", builderFactory.createObjectBuilder() + .add("d", "e") + .add("f", "g")) + .build())); + } + + @Test + public void jsonMergeDiff() { + assertEquals( + builderFactory.createObjectBuilder() + .add("a", "z") + .add("c", builderFactory.createObjectBuilder() + .addNull("f")) + .build(), + jsonLogic.apply( + builderFactory.createObjectBuilder() + .add("jsonmergediff", builderFactory.createObjectBuilder() + .add("a", "b") + .add("c", builderFactory.createObjectBuilder() + .add("d", "e") + .add("f", "g"))) + .build(), + builderFactory.createArrayBuilder() + .add(builderFactory.createObjectBuilder() + .add("a", "z") + .add("c", builderFactory.createObjectBuilder() + .add("d", "e")) + .build()) + .add(builderFactory.createObjectBuilder()) + .build())); + } + + @Test public void varObjectString() { assertEquals(Json.createValue("b"), jsonLogic.apply( builderFactory.createObjectBuilder() diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index e0f75d5..867cec7 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -596,6 +596,8 @@ jsonLogic.registerOperator( (jsonLogic, config, args) -> log.info(String.valueOf(jsonLogic.apply(config, args))); ]]></pre> +Note that by default the set of standard JSON Logic operators is enriched with JSON-P jsonpatch, json merge diff and json merge patch operators. + ### OSGi JAX-RS Whiteboard Though Johnzon artifacts are OSGi bundles to begin with, this module provides further integration with the [OSGi JAX-RS Whiteboard](https://osgi.org/specification/osgi.cmpn/7.0.0/service.jaxrs.html) and [OSGi CDI Integration](https://osgi.org/specification/osgi.enterprise/7.0.0/service.cdi.html) specifications.