You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2019/10/01 17:04:07 UTC
[johnzon] branch master updated: JOHNZON-285 enable to support a
fastpath for a reader implementing Supplier and a writer
implementing a Consumer
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 d721074 JOHNZON-285 enable to support a fastpath for a reader implementing Supplier<JsonObject> and a writer implementing a Consumer<JsonValue>
d721074 is described below
commit d721074adc406c2e5e3112e939379c5989f247a3
Author: Romain Manni-Bucau <rm...@apache.org>
AuthorDate: Tue Oct 1 19:03:45 2019 +0200
JOHNZON-285 enable to support a fastpath for a reader implementing Supplier<JsonObject> and a writer implementing a Consumer<JsonValue>
---
.../org/apache/johnzon/jsonb/JohnzonJsonb.java | 69 ++++++++++++++++++----
.../johnzon/jsonb/extension/JsonValueReader.java | 26 ++++++--
.../johnzon/jsonb/extension/JsonValueWriter.java | 27 +++++++--
.../java/org/apache/johnzon/mapper/Mapper.java | 13 +++-
src/site/markdown/index.md | 2 +-
5 files changed, 113 insertions(+), 24 deletions(-)
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonJsonb.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonJsonb.java
index 7eae65e..ba2d8b2 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonJsonb.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonJsonb.java
@@ -20,8 +20,6 @@ package org.apache.johnzon.jsonb;
import org.apache.johnzon.mapper.util.ArrayUtil;
import org.apache.johnzon.jsonb.api.experimental.JsonbExtension;
-import org.apache.johnzon.jsonb.extension.JsonValueReader;
-import org.apache.johnzon.jsonb.extension.JsonValueWriter;
import org.apache.johnzon.mapper.JsonObjectGenerator;
import org.apache.johnzon.mapper.Mapper;
import org.apache.johnzon.mapper.MapperException;
@@ -43,17 +41,21 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.Collection;
+import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
-// TODO: Optional handling for lists (and arrays)?
public class JohnzonJsonb implements Jsonb, AutoCloseable, JsonbExtension {
private final Mapper delegate;
private final boolean ijson;
private final Consumer<JohnzonJsonb> onClose;
+ private final Map<Class<?>, Boolean> structureAwareIo = new ConcurrentHashMap<>();
public JohnzonJsonb(final Mapper build, final boolean ijson, final Consumer<JohnzonJsonb> onClose) {
this.delegate = build;
@@ -143,18 +145,28 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable, JsonbExtension {
@Override
public <T> T fromJson(final Reader reader, final Class<T> type) throws JsonbException {
- if (JsonValueReader.class.isInstance(reader)) {
- return delegate.readObject(JsonValueReader.class.cast(reader).getInput(), type);
- }
-
+ final boolean valueProvider = isValueProvider(reader);
try {
if (isArray(type)) {
+ if (valueProvider) {
+ return delegate.readObject(((Supplier<JsonValue>) reader).get(), type);
+ }
return delegate.readTypedArray(reader, type.getComponentType(), type);
} else if (JsonArray.class == type) {
+ if (valueProvider) {
+ return delegate.readObject(((Supplier<JsonValue>) reader).get(), type);
+ }
return (T) delegate.readJsonArray(reader);
} else if (Collection.class.isAssignableFrom(type)) {
+ if (valueProvider) {
+ return delegate.readObject(((Supplier<JsonValue>) reader).get(), type);
+ }
return (T) delegate.readCollection(reader, new JohnzonParameterizedType(type, Object.class));
}
+ if (valueProvider) {
+ return delegate.readObject(((Supplier<JsonValue>) reader).get(), type);
+ }
+
final Type mappingType = unwrapPrimitiveOptional(type);
final Object object = delegate.readObject(reader, mappingType);
if (mappingType != type) {
@@ -168,8 +180,8 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable, JsonbExtension {
@Override
public <T> T fromJson(final Reader reader, final Type runtimeType) throws JsonbException {
- if (JsonValueReader.class.isInstance(reader)) {
- return delegate.readObject(JsonValueReader.class.cast(reader).getInput(), runtimeType);
+ if (isValueProvider(reader)) {
+ return delegate.readObject(((Supplier<JsonStructure>) reader).get(), runtimeType);
}
try {
@@ -323,8 +335,8 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable, JsonbExtension {
@Override
public void toJson(final Object inObject, final Writer writer) throws JsonbException {
- if (JsonValueWriter.class.isInstance(writer)) {
- JsonValueWriter.class.cast(writer).setResult(delegate.toStructure(inObject));
+ if (isValueConsumer(writer)) {
+ Consumer.class.cast(writer).accept(delegate.toStructure(inObject));
return;
}
@@ -342,8 +354,8 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable, JsonbExtension {
@Override
public void toJson(final Object inObject, final Type runtimeType, final Writer writer) throws JsonbException {
- if (JsonValueWriter.class.isInstance(writer)) {
- JsonValueWriter.class.cast(writer).setResult(delegate.toStructure(inObject));
+ if (isValueConsumer(writer)) {
+ Consumer.class.cast(writer).accept(delegate.toStructure(inObject));
return;
}
@@ -520,4 +532,35 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable, JsonbExtension {
return jsonObjectGenerator.getResult();
}
}
+
+ private boolean isValueProvider(final Reader reader) {
+ final Class<? extends Reader> key = reader.getClass();
+ Boolean exists = structureAwareIo.get(key);
+ if (exists == null) {
+ exists = matchesType(key, Supplier.class);
+ structureAwareIo.putIfAbsent(key, exists);
+ }
+ return exists;
+ }
+
+ private boolean isValueConsumer(final Writer writer) {
+ final Class<? extends Writer> key = writer.getClass();
+ Boolean exists = structureAwareIo.get(key);
+ if (exists == null) {
+ exists = matchesType(writer.getClass(), Consumer.class);
+ structureAwareIo.putIfAbsent(key, exists);
+ }
+ return exists;
+ }
+
+ private boolean matchesType(final Class<?> type, final Class<?> rawType) {
+ return rawType.isAssignableFrom(type) &&
+ Stream.of(type.getGenericInterfaces())
+ .filter(ParameterizedType.class::isInstance)
+ .map(ParameterizedType.class::cast)
+ .anyMatch(pt -> pt.getRawType() == rawType &&
+ pt.getActualTypeArguments().length == 1 &&
+ Class.class.isInstance(pt.getActualTypeArguments()[0]) &&
+ JsonValue.class.isAssignableFrom(Class.class.cast(pt.getActualTypeArguments()[0])));
+ }
}
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueReader.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueReader.java
index 222a6e0..c4899d3 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueReader.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueReader.java
@@ -18,12 +18,17 @@
*/
package org.apache.johnzon.jsonb.extension;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.function.Supplier;
import javax.json.JsonStructure;
-public class JsonValueReader<T> extends Reader {
+public class JsonValueReader<T> extends Reader implements Supplier<JsonStructure> {
private final JsonStructure input;
+ private ByteArrayInputStream fallbackDelegate;
private T result;
public JsonValueReader(final JsonStructure input) {
@@ -32,22 +37,35 @@ public class JsonValueReader<T> extends Reader {
@Override
public int read(final char[] cbuf, final int off, final int len) {
- throw new UnsupportedOperationException();
+ if (fallbackDelegate == null) {
+ fallbackDelegate = new ByteArrayInputStream(input.toString().getBytes(StandardCharsets.UTF_8));
+ }
+ return fallbackDelegate.read();
}
@Override
- public void close() {
- // no-op
+ public void close() throws IOException {
+ if (fallbackDelegate != null) {
+ fallbackDelegate.close();
+ }
}
+ @Override
+ public JsonStructure get() {
+ return input;
+ }
+
+ @Deprecated
public JsonStructure getInput() {
return input;
}
+ @Deprecated
public T getResult() {
return result;
}
+ @Deprecated
public void setResult(final T result) {
this.result = result;
}
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueWriter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueWriter.java
index a861658..fbb9404 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueWriter.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueWriter.java
@@ -18,18 +18,26 @@
*/
package org.apache.johnzon.jsonb.extension;
+import java.io.StringReader;
import java.io.Writer;
+import java.util.function.Consumer;
+import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.json.JsonReader;
import javax.json.JsonValue;
-public class JsonValueWriter extends Writer {
+public class JsonValueWriter extends Writer implements Consumer<JsonValue> {
private JsonValue result;
+ private StringBuilder fallbackOutput;
@Override
public void write(final char[] cbuf, final int off, final int len) {
- throw new UnsupportedOperationException();
+ if (fallbackOutput == null) {
+ fallbackOutput = new StringBuilder();
+ }
+ fallbackOutput.append(cbuf, off, len);
}
@Override
@@ -42,19 +50,30 @@ public class JsonValueWriter extends Writer {
flush();
}
+ @Deprecated
public void setResult(final JsonValue result) {
this.result = result;
}
public JsonValue getResult() {
+ if (result == null && fallbackOutput != null) {
+ try (final JsonReader reader = Json.createReader(new StringReader(fallbackOutput.toString()))) {
+ result = reader.readValue();
+ }
+ }
return result;
}
public JsonObject getObject() {
- return result.asJsonObject();
+ return getResult().asJsonObject();
}
public JsonArray getArray() {
- return result.asJsonArray();
+ return getResult().asJsonArray();
+ }
+
+ @Override
+ public void accept(final JsonValue jsonValue) {
+ this.result = jsonValue;
}
}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index e8ae5cc..4a9639c 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -250,11 +250,20 @@ public class Mapper implements Closeable {
return writer.toString();
}
- public <T> T readObject(final JsonStructure value, final Type clazz) {
+ public <T> T readObject(final JsonValue value, final Type clazz) {
return new MappingParserImpl(config, mappings, new JsonReader() {
@Override
public JsonStructure read() {
- return value;
+ switch (value.getValueType()) {
+ case STRING:
+ case FALSE:
+ case TRUE:
+ case NULL:
+ case NUMBER:
+ throw new UnsupportedOperationException("use readValue()");
+ default:
+ return JsonStructure.class.cast(readValue());
+ }
}
@Override
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 91f3f9f..764c722 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -326,7 +326,7 @@ Default will be picked from the current available API. Finally, this behavior on
#### Integration with `JsonValue`
-You can use some optimization to map a `JsonObject` to a POJO using Johnzon `JsonValueReader` and `JsonValueWriter`:
+You can use some optimization to map a `JsonObject` to a POJO using Johnzon `JsonValueReader` - or any implementation of `Reader` implementing `Supplier<JsonStructure>` - and `JsonValueWriter` - or any implementation of `Writer` implementing `Consumer<JsonValue>` -:
<pre class="prettyprint linenums"><![CDATA[
final JsonValueReader<Simple> reader = new JsonValueReader<>(Json.createObjectBuilder().add("value", "simple").build());