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 7001b97 [JOHNZON-329] make jsonlogic completionstage friendly
7001b97 is described below
commit 7001b971b72a7352f2b27f1b9a445e6fe533dd47
Author: Romain Manni-Bucau <[email protected]>
AuthorDate: Thu Dec 17 10:23:03 2020 +0100
[JOHNZON-329] make jsonlogic completionstage friendly
---
.../org/apache/johnzon/jsonb/CdiAdapterTest.java | 24 ++++--
.../johnzon/jsonb/JohnzonConverterInJsonbTest.java | 4 +-
.../apache/johnzon/jsonlogic/JohnzonJsonLogic.java | 41 +++++++++-
.../spi/{Operator.java => AsyncOperator.java} | 23 +++++-
.../org/apache/johnzon/jsonlogic/spi/Operator.java | 14 ++++
.../johnzon/jsonlogic/JohnzonJsonLogicTest.java | 90 ++++++++++++++++++++++
pom.xml | 15 ++--
7 files changed, 191 insertions(+), 20 deletions(-)
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
index 79685bb..d071541 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
@@ -20,10 +20,14 @@ package org.apache.johnzon.jsonb;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.config.WebBeansFinder;
-import org.apache.webbeans.lifecycle.test.OpenWebBeansTestLifeCycle;
-import
org.apache.webbeans.lifecycle.test.OpenWebBeansTestMetaDataDiscoveryService;
+import org.apache.webbeans.corespi.se.DefaultScannerService;
+import org.apache.webbeans.lifecycle.StandaloneLifeCycle;
import org.apache.webbeans.proxy.OwbNormalScopeProxy;
+import org.apache.webbeans.spi.ContainerLifecycle;
+import org.apache.webbeans.spi.ScannerService;
import org.apache.webbeans.util.WebBeansUtil;
+import org.apache.xbean.finder.AnnotationFinder;
+import org.apache.xbean.finder.archive.ClassesArchive;
import org.junit.Test;
import javax.enterprise.context.ApplicationScoped;
@@ -32,8 +36,9 @@ import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.adapter.JsonbAdapter;
import javax.json.bind.annotation.JsonbTypeAdapter;
+import java.util.Properties;
-import static java.util.Arrays.asList;
+import static java.util.Collections.singletonMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -42,10 +47,14 @@ public class CdiAdapterTest {
@Test
public void run() {
WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader());
- final OpenWebBeansTestLifeCycle testLifecycle = new
OpenWebBeansTestLifeCycle();
- final WebBeansContext ctx = WebBeansContext.currentInstance();
- final OpenWebBeansTestMetaDataDiscoveryService discoveryService =
OpenWebBeansTestMetaDataDiscoveryService.class.cast(ctx.getScannerService());
- discoveryService.deployClasses(asList(Service.class,
ModelAdapter.class));
+ final ContainerLifecycle testLifecycle = new StandaloneLifeCycle();
+ new WebBeansContext(singletonMap(
+ ScannerService.class, new DefaultScannerService() {
+ @Override
+ protected AnnotationFinder initFinder() {
+ return new AnnotationFinder(new
ClassesArchive(Service.class, ModelAdapter.class));
+ }
+ }), new Properties());
testLifecycle.startApplication(null);
try {
Jsonb jsonb = JsonbBuilder.create();
@@ -57,6 +66,7 @@ public class CdiAdapterTest {
}
} finally {
testLifecycle.stopApplication(null);
+
WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader());
}
}
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
index c72cac5..4ce2e13 100644
---
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
+++
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
@@ -53,7 +53,7 @@ public class JohnzonConverterInJsonbTest {
assertNotNull(json);
TestDTO deserialized = jsonb.fromJson(json, TestDTO.class);
- assertEquals(dto.instant, deserialized.instant);
+ assertEquals(dto.instant.toEpochMilli(),
deserialized.instant.toEpochMilli());
}
@Test
@@ -67,7 +67,7 @@ public class JohnzonConverterInJsonbTest {
assertNotNull(json);
TestDTOWithOC deserialized = jsonb.fromJson(json, TestDTOWithOC.class);
- assertEquals(deserialized.dto.instant, dto.dto.instant);
+ assertEquals(deserialized.dto.instant.toEpochMilli(),
dto.dto.instant.toEpochMilli());
}
public static class TestDTOWithOC {
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 691146c..9691c82 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
@@ -35,12 +35,15 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
import java.util.function.BiPredicate;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;
import static java.util.Collections.emptyMap;
+import static java.util.concurrent.CompletableFuture.completedFuture;
import static java.util.stream.Collectors.joining;
public class JohnzonJsonLogic {
@@ -82,16 +85,42 @@ public class JohnzonJsonLogic {
final Set<String> keys = object.keySet();
if (keys.size() != 1) {
- throw new IllegalArgumentException("Invalid argument, multiple
keys found: " + keys);
+ throw invalidArgument(keys);
}
final String operator = keys.iterator().next();
final Operator impl = operators.get(operator);
if (impl == null) {
- throw new IllegalArgumentException("Missing operator '" + operator
+ "'");
+ throw missingOperator(operator);
}
return impl.apply(this, object.get(operator), args);
}
+ public CompletionStage<JsonValue> applyStage(final JsonValue logic, final
JsonValue args) {
+ if (logic.getValueType() != JsonValue.ValueType.OBJECT) {
+ return completedFuture(logic);
+ }
+
+ final JsonObject object = logic.asJsonObject();
+ if (object.size() > 1) {
+ return completedFuture(object);
+ }
+
+ final Set<String> keys = object.keySet();
+ if (keys.size() != 1) {
+ final CompletableFuture<JsonValue> promise = new
CompletableFuture<>();
+ promise.completeExceptionally(invalidArgument(keys));
+ return promise;
+ }
+ final String operator = keys.iterator().next();
+ final Operator impl = operators.get(operator);
+ if (impl == null) {
+ final CompletableFuture<JsonValue> promise = new
CompletableFuture<>();
+ promise.completeExceptionally(missingOperator(operator));
+ return promise;
+ }
+ return impl.applyStage(this, object.get(operator), args);
+ }
+
public boolean isTruthy(final JsonValue value) {
return !isFalsy(value);
}
@@ -206,6 +235,14 @@ public class JohnzonJsonLogic {
return this;
}
+ private IllegalArgumentException invalidArgument(final Set<String> keys) {
+ return new IllegalArgumentException("Invalid argument, multiple keys
found: " + keys);
+ }
+
+ private IllegalArgumentException missingOperator(final String operator) {
+ return new IllegalArgumentException("Missing operator '" + operator +
"'");
+ }
+
private JsonValue minImpl(final JohnzonJsonLogic logic, final JsonValue
config, final JsonValue params) {
if (config.getValueType() != JsonValue.ValueType.ARRAY) {
throw new IllegalArgumentException("min only supports arrays: '" +
config + "'");
diff --git
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/AsyncOperator.java
similarity index 52%
copy from
johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
copy to
johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/AsyncOperator.java
index 8531e0b..42e2d22 100644
---
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
+++
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/AsyncOperator.java
@@ -21,8 +21,27 @@ package org.apache.johnzon.jsonlogic.spi;
import org.apache.johnzon.jsonlogic.JohnzonJsonLogic;
import javax.json.JsonValue;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ExecutionException;
@FunctionalInterface
-public interface Operator {
- JsonValue apply(JohnzonJsonLogic logic, JsonValue config, JsonValue
params);
+public interface AsyncOperator extends Operator {
+ @Override
+ CompletionStage<JsonValue> applyStage(JohnzonJsonLogic logic, JsonValue
config, JsonValue params);
+
+ @Override
+ default JsonValue apply(JohnzonJsonLogic logic, JsonValue config,
JsonValue params) {
+ try {
+ return applyStage(logic, config,
params).toCompletableFuture().get();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ } catch (ExecutionException e) {
+ final Throwable cause = e.getCause();
+ if (RuntimeException.class.isInstance(cause)) {
+ throw RuntimeException.class.cast(cause);
+ }
+ throw new IllegalStateException(cause);
+ }
+ }
}
diff --git
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
index 8531e0b..a66c16f 100644
---
a/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
+++
b/johnzon-jsonlogic/src/main/java/org/apache/johnzon/jsonlogic/spi/Operator.java
@@ -21,8 +21,22 @@ package org.apache.johnzon.jsonlogic.spi;
import org.apache.johnzon.jsonlogic.JohnzonJsonLogic;
import javax.json.JsonValue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+import static java.util.concurrent.CompletableFuture.completedFuture;
@FunctionalInterface
public interface Operator {
+ default CompletionStage<JsonValue> applyStage(JohnzonJsonLogic logic,
JsonValue config, JsonValue params) {
+ try {
+ return completedFuture(apply(logic, config, params));
+ } catch (final RuntimeException re) {
+ final CompletableFuture<JsonValue> promise = new
CompletableFuture<>();
+ promise.completeExceptionally(re);
+ return promise;
+ }
+ }
+
JsonValue apply(JohnzonJsonLogic logic, JsonValue config, JsonValue
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 49295b3..f126cfd 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
@@ -18,12 +18,18 @@
*/
package org.apache.johnzon.jsonlogic;
+import org.apache.johnzon.jsonlogic.spi.AsyncOperator;
+import org.apache.johnzon.jsonlogic.spi.Operator;
import org.junit.Test;
import javax.json.Json;
import javax.json.JsonBuilderFactory;
import javax.json.JsonObject;
import javax.json.JsonValue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import static java.util.Collections.emptyMap;
import static org.junit.Assert.assertEquals;
@@ -33,6 +39,90 @@ public class JohnzonJsonLogicTest {
private final JsonBuilderFactory builderFactory =
Json.createBuilderFactory(emptyMap());
@Test
+ public void stage() throws InterruptedException {
+ // if the async exec is too immediate we will execute the thenAccept
callback in main thread
+ // which is not the goal of this test so let's ensure we are in the
expected case
+ final CountDownLatch waitChainReady = new CountDownLatch(1);
+
+ final JohnzonJsonLogic jsonLogic = new JohnzonJsonLogic()
+ .registerOperator("async", new Operator() {
+ @Override
+ public CompletionStage<JsonValue> applyStage(final
JohnzonJsonLogic logic,
+ final
JsonValue config,
+ final
JsonValue params) {
+ return logic.applyStage(
+
builderFactory.createObjectBuilder().add("async2", "ok").build(),
+ builderFactory.createObjectBuilder().add("p2",
"1").build())
+ .thenApplyAsync(
+ previous ->
builderFactory.createObjectBuilder()
+ .add("thread",
Thread.currentThread().getName())
+ .add("config", config)
+ .add("params", params)
+ .add("exec2", previous)
+ .build(),
+ r -> new Thread(r, "async").start());
+ }
+
+ @Override
+ public JsonValue apply(final JohnzonJsonLogic logic, final
JsonValue config, final JsonValue params) {
+ throw new UnsupportedOperationException();
+ }
+ })
+ .registerOperator("async2", new AsyncOperator() {
+ @Override
+ public CompletionStage<JsonValue> applyStage(final
JohnzonJsonLogic logic,
+ final
JsonValue config,
+ final
JsonValue params) {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ waitChainReady.await();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ return builderFactory.createObjectBuilder()
+ .add("thread2",
Thread.currentThread().getName())
+ .add("config2", config)
+ .add("params2", params)
+ .build();
+ }, r -> new Thread(r, "async2").start());
+ }
+
+ @Override
+ public JsonValue apply(final JohnzonJsonLogic logic, final
JsonValue config, final JsonValue params) {
+ throw new UnsupportedOperationException();
+ }
+ });
+
+ final CountDownLatch latch = new CountDownLatch(1); // if we use
Future.get we break stage threading
+ final AtomicReference<JsonValue> output = new AtomicReference<>();
+ jsonLogic
+ .applyStage(
+ builderFactory.createObjectBuilder()
+ .add("async", "a")
+ .build(),
+ builderFactory.createObjectBuilder()
+ .add("p1", "0")
+ .build())
+ .thenAccept(result -> {
+ output.set(builderFactory.createObjectBuilder()
+ .add("exec1", result)
+ .add("thenSyncThread",
Thread.currentThread().getName())
+ .build());
+ latch.countDown();
+ });
+ waitChainReady.countDown();
+ latch.await();
+ assertEquals("" +
+ "{" +
+
"\"exec1\":{\"thread\":\"async\",\"config\":\"a\",\"params\":{\"p1\":\"0\"}," +
+
"\"exec2\":{\"thread2\":\"async2\",\"config2\":\"ok\",\"params2\":{\"p2\":\"1\"}}},"
+
+ "\"thenSyncThread\":\"async\"" +
+ "}" +
+ "",
+ output.get().toString());
+ }
+
+ @Test
public void varObjectString() {
assertEquals(Json.createValue("b"), jsonLogic.apply(
builderFactory.createObjectBuilder()
diff --git a/pom.xml b/pom.xml
index 38d33fa..6a44f98 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,12 +45,11 @@
<felix.plugin.version>4.0.0</felix.plugin.version>
<bnd.version.policy>[$(version;==;$(@)),$(version;+;$(@)))</bnd.version.policy>
<java-compile.version>1.8</java-compile.version>
- <cxf.version>3.0.0</cxf.version>
- <javadoc.params /> <!-- for java 8 set disable doclint (by profile) -->
+ <cxf.version>3.4.1</cxf.version>
<checkstyle.version>2.15</checkstyle.version> <!-- checkstyle > 2.15
version do not support java 6 -->
<!-- JVM values for surefire plugin -->
<surefire.jvm.params>-Xms1024m -Xmx2048m
-Dfile.encoding=UTF-8</surefire.jvm.params>
- <owb.version>1.7.5</owb.version>
+ <owb.version>2.0.20</owb.version>
</properties>
<modules>
@@ -345,7 +344,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
- <version>2.10.3</version>
+ <version>3.2.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
@@ -354,7 +353,11 @@
</goals>
<configuration>
<show>private</show>
- <additionalparam>${javadoc.params}</additionalparam> <!-- maven
plugin generated a HelpMojo with malformed javadoc -->
+ <detectJavaApiLink>false</detectJavaApiLink>
+ <detectLinks>false</detectLinks>
+ <detectOfflineLinks>false</detectOfflineLinks>
+ <doclint>none</doclint>
+ <source>8</source>
</configuration>
</execution>
</executions>
@@ -508,7 +511,6 @@
<configuration>
<notimestamp>true</notimestamp>
<show>private</show>
- <additionalparam>${javadoc.params}</additionalparam> <!-- maven
plugin generated a HelpMojo with malformed javadoc -->
</configuration>
<reportSets>
<reportSet>
@@ -762,7 +764,6 @@
</activation>
<properties>
<checkstyle.version>2.17</checkstyle.version>
- <javadoc.params>-Xdoclint:none</javadoc.params>
</properties>
</profile>
</profiles>