fix the johnzon-core dependency in mapper/jsonb module + use BoundedOutputStreamWriter in Snippet
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/IODescriptor.java b/johnzon-core/src/main/java/org/apache/johnzon/core/Buffered.java
similarity index 92%
rename from johnzon-core/src/main/java/org/apache/johnzon/core/IODescriptor.java
rename to johnzon-core/src/main/java/org/apache/johnzon/core/Buffered.java
index 1581ce0..40cabfb 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/IODescriptor.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/Buffered.java
@@ -26,7 +26,7 @@
*
* @since 1.2.17
*/
-public interface IODescriptor {
+public interface Buffered { // https://github.com/apache/johnzon/pull/84#discussion_r860563179 for the naming ;)
/**
* The buffer size used by this stream while reading input or before writing
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
index 0e5fac2..646fea4 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
@@ -56,8 +56,9 @@
super(config, SUPPORTED_CONFIG_KEYS, null);
this.pretty = getBool(JsonGenerator.PRETTY_PRINTING, false);
this.boundedOutputStreamWriter = getInt(BOUNDED_OUTPUT_STREAM_WRITER_LEN, -1);
- this.defaultEncoding = ofNullable(getString(ENCODING, null))
- .map(Charset::forName)
+ this.defaultEncoding = ofNullable(config)
+ .map(c -> c.get(ENCODING))
+ .map(it -> Charset.class.isInstance(it) ? Charset.class.cast(it) : Charset.forName(it.toString()))
.orElse(UTF_8);
final int bufferSize = getInt(GENERATOR_BUFFER_LENGTH, DEFAULT_GENERATOR_BUFFER_LENGTH);
@@ -96,12 +97,16 @@
return Collections.unmodifiableMap(internalConfig);
}
+ public Charset getDefaultEncoding() {
+ return defaultEncoding;
+ }
+
private BufferStrategy.BufferProvider<char[]> getBufferProvider(final Flushable flushable) {
- if (!(flushable instanceof IODescriptor)) {
+ if (!(flushable instanceof Buffered)) {
return buffer.provider;
}
- final int bufferSize = IODescriptor.class.cast(flushable).bufferSize();
+ final int bufferSize = Buffered.class.cast(flushable).bufferSize();
if (customBuffer != null && customBuffer.size == bufferSize) {
return customBuffer.provider;
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java b/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
index 5df0b3a..23ed634 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
@@ -16,6 +16,9 @@
*/
package org.apache.johnzon.core;
+import org.apache.johnzon.core.io.BoundedOutputStreamWriter;
+
+import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonValue;
@@ -24,13 +27,11 @@
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
-import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
-import java.util.function.Supplier;
-import static org.apache.johnzon.core.JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH;
+import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Constructs short snippets of serialized JSON text representations of
@@ -41,26 +42,9 @@
* is therefore safe to use regardless of the size of the JsonValue.
*/
public class Snippet {
-
private final int max;
private final JsonGeneratorFactory generatorFactory;
- // IMPORTANT: should NOT be used inside johnzon project itself which should *always*
- // use a contextual JsonGeneratorFactory - keep in mind we are not johnzon-core dependent
- // not JSON dependent (some JsonGeneratorFactory can issue yaml or binary for ex)
- /**
- * This constructor should be used only in static or other scenarios were
- * there is no JsonGeneratorFactory instance in scope.
- *
- * @param max the maximum length of the serialized json produced via of()
- */
- public Snippet(final int max) {
- this(max, new JsonGeneratorFactoryImpl(new HashMap<String, Object>() {
- {
- this.put(GENERATOR_BUFFER_LENGTH, max);
- }
- }));
- }
/**
* This is the preferred approach to using Snippet in any context where
@@ -85,10 +69,27 @@
* @return a potentially truncated json text
*/
public String of(final JsonValue value) {
- try (final Buffer buffer = new Buffer()) {
- buffer.write(value);
- return buffer.get();
+ final Buffer buffer = new Buffer();
+ try (final Buffer b = buffer) {
+ b.write(value);
}
+ return buffer.get();
+ }
+
+ // IMPORTANT: should NOT be used inside johnzon project itself which should *always*
+ // use a contextual JsonGeneratorFactory - keep in mind we are not johnzon-core dependent
+ // not JSON dependent (some JsonGeneratorFactory can issue yaml or binary for ex)
+ /**
+ * This factory should be used only in static or other scenarios were
+ * there is no JsonGeneratorFactory instance in scope - ie external code.
+ *
+ * @param max the maximum length of the serialized json produced via of()
+ */
+ public static Snippet of(final int max) {
+ final Map<String, Object> properties = new HashMap<>();
+ properties.put("org.apache.johnzon.default-char-buffer-generator", max);
+ properties.put("org.apache.johnzon.boundedoutputstreamwriter", max);
+ return new Snippet(max, Json.createGeneratorFactory(properties));
}
/**
@@ -102,12 +103,58 @@
* is a JsonGeneratorFactory instance in scope. For those scenarios
* use the constructor that accepts a JsonGeneratorFactory instead.
*
- * @param value the JsonValue to be serialized as json text
* @param max the maximum length of the serialized json text
+ * @param value the JsonValue to be serialized as json text
* @return a potentially truncated json text
*/
- public static String of(final JsonValue value, final int max) {
- return new Snippet(max).of(value);
+ public static String of(final int max, final JsonValue value) {
+ return of(max).of(value);
+ }
+
+ // skips some methods using a buffer
+ private static abstract class PassthroughWriter extends Writer {
+ @Override
+ public void write(final char[] cbuf) throws IOException {
+ write(cbuf, 0, cbuf.length);
+ }
+
+ @Override
+ public void write(final String str) throws IOException {
+ write(str.toCharArray(), 0, str.length());
+ }
+
+ @Override
+ public void write(final String str, final int off, final int len) throws IOException {
+ write(str.toCharArray(), 0, len);
+ }
+
+ @Override
+ public Writer append(final CharSequence csq) throws IOException {
+ write(csq.toString().toCharArray(), 0, csq.length());
+ return this;
+ }
+
+ @Override
+ public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
+ write(csq.toString().toCharArray(), start, end);
+ return this;
+ }
+
+ @Override
+ public Writer append(final char c) throws IOException {
+ write(new char[]{c}, 0, 1);
+ return this;
+ }
+
+ @Override
+ public void flush() throws IOException {
+ // no-op
+ }
+
+ @Override
+ public void close() throws IOException {
+ // no-op
+ }
}
/**
@@ -126,15 +173,13 @@
* need 50 bytes. We could potentially optimize this code so the
* buffer held by JsonGeneratorImpl is also the maxSnippetLength.
*/
- class Buffer implements Closeable {
+ private class Buffer implements Closeable {
private final JsonGenerator generator;
private final SnippetWriter snippet;
- private Runnable flush;
private Buffer() {
this.snippet = new SnippetWriter(max);
this.generator = generatorFactory.createGenerator(snippet);
- this.flush = generator::flush;
}
private void write(final JsonValue value) {
@@ -222,13 +267,11 @@
}
private boolean terminate() {
- flush.run();
return snippet.terminate();
}
private String get() {
- generator.flush();
- return snippet.isTruncated() ? snippet.get() + "..." : snippet.get();
+ return snippet.get() + (snippet.isTruncated() ? "..." : "");
}
@Override
@@ -249,30 +292,20 @@
* If the last write brought us over the max length, the
* state will be Truncated.
*/
- class SnippetWriter extends Writer implements IODescriptor {
-
+ class SnippetWriter extends PassthroughWriter implements Buffered {
private final ByteArrayOutputStream buffer;
- private Mode mode;
- private Supplier<Integer> bufferSize;
+ private final int max;
+ private PassthroughWriter mode;
public SnippetWriter(final int max) {
- final int size = Math.min(max, 8192);
-
- this.buffer = new ByteArrayOutputStream(size);
- this.mode = new Writing(max, new OutputStreamWriter(buffer));
-
- /*
- * The first time the buffer size is requested, disable flushing
- * as we know our requested buffer size will be respected
- */
- this.bufferSize = () -> {
- // disable flushing
- flush = () -> {
- };
- // future calls can just return the size
- bufferSize = () -> size;
- return size;
- };
+ this.max = max;
+ this.buffer = new ByteArrayOutputStream(max);
+ this.mode = new Writing(max, new BoundedOutputStreamWriter(
+ buffer,
+ JsonGeneratorFactoryImpl.class.isInstance(generatorFactory) ?
+ JsonGeneratorFactoryImpl.class.cast(generatorFactory).getDefaultEncoding() :
+ UTF_8,
+ max));
}
public String get() {
@@ -281,7 +314,7 @@
@Override
public int bufferSize() {
- return bufferSize.get();
+ return max;
}
/**
@@ -325,17 +358,7 @@
mode.close();
}
- abstract class Mode extends Writer {
- @Override
- public void flush() throws IOException {
- }
-
- @Override
- public void close() throws IOException {
- }
- }
-
- class Writing extends Mode {
+ class Writing extends PassthroughWriter {
private final int max;
private int count;
private final Writer writer;
@@ -381,7 +404,7 @@
writer.close();
}
- private void maxReached(final Mode mode) throws IOException {
+ private void maxReached(final PassthroughWriter mode) throws IOException {
SnippetWriter.this.mode = mode;
writer.flush();
writer.close();
@@ -392,8 +415,7 @@
* Signifies the last write was fully written, but there is
* no more space for future writes.
*/
- class Completed extends Mode {
-
+ class Completed extends PassthroughWriter {
@Override
public void write(final char[] cbuf, final int off, final int len) throws IOException {
if (len > 0) {
@@ -406,9 +428,10 @@
* Signifies the last write was not completely written and there was
* no more space for this or future writes.
*/
- class Truncated extends Mode {
+ class Truncated extends PassthroughWriter {
@Override
public void write(final char[] cbuf, final int off, final int len) throws IOException {
+ // no-op
}
}
}
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/Types.java b/johnzon-core/src/main/java/org/apache/johnzon/core/Types.java
index d06d27f..f7fb6a0 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/Types.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/Types.java
@@ -45,21 +45,6 @@
return new ParameterizedTypeImpl(parameterizedClass, resolveArgumentTypes(klass, parameterizedClass));
}
- public Class<?> findParamType(final ParameterizedType type, final Class<?> expectedWrapper) {
- if (type.getActualTypeArguments().length != 1) {
- return null;
- }
- final Class<?> asClass = asClass(type.getRawType());
- if (asClass == null || !expectedWrapper.isAssignableFrom(asClass)) {
- return null;
- }
- return asClass(type.getActualTypeArguments()[0]);
- }
-
- public Class<?> asClass(final Type type) {
- return Class.class.isInstance(type) ? Class.class.cast(type) : null;
- }
-
private Type[] resolveArgumentTypes(Type type, Class<?> parameterizedClass) {
if (type instanceof Class<?>) {
return resolveArgumentTypes((Class<?>) type, parameterizedClass);
diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/SnippetTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/SnippetTest.java
index 9d008ff..017d332 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/SnippetTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/SnippetTest.java
@@ -277,7 +277,7 @@
* Serialize the json value, truncating nothing
*/
final TrackingJsonGeneratorFactory full = new TrackingJsonGeneratorFactory();
- new Snippet(Integer.MAX_VALUE, full).of(object);
+ new Snippet(8192, full).of(object);
/*
* Assert that the calls made in truncated version are less
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
index 5afe718..2e2f2a4 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -18,15 +18,12 @@
*/
package org.apache.johnzon.jsonb;
-import org.apache.johnzon.core.AbstractJsonFactory;
-import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
-import org.apache.johnzon.core.JsonParserFactoryImpl;
-import org.apache.johnzon.core.Types;
import org.apache.johnzon.jsonb.adapter.JsonbEnumAdapter;
import org.apache.johnzon.jsonb.api.experimental.PolymorphicConfig;
import org.apache.johnzon.jsonb.cdi.CDIs;
import org.apache.johnzon.jsonb.converter.JohnzonJsonbAdapter;
import org.apache.johnzon.jsonb.factory.SimpleJohnzonAdapterFactory;
+import org.apache.johnzon.jsonb.reflect.Types;
import org.apache.johnzon.jsonb.serializer.JohnzonDeserializationContext;
import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext;
import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory;
@@ -442,8 +439,9 @@
if (config == null) {
return map;
}
- config.getProperty(JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH).ifPresent(b -> map.put(JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH, b));
- config.getProperty(AbstractJsonFactory.BUFFER_STRATEGY).ifPresent(b -> map.put(AbstractJsonFactory.BUFFER_STRATEGY, b));
+ config.getProperty("org.apache.johnzon.default-char-buffer-generator").ifPresent(b -> map.put("org.apache.johnzon.default-char-buffer-generator", b));
+ config.getProperty("org.apache.johnzon.boundedoutputstreamwriter").ifPresent(b -> map.put("org.apache.johnzon.boundedoutputstreamwriter", b));
+ config.getProperty("org.apache.johnzon.buffer-strategy").ifPresent(b -> map.put("org.apache.johnzon.buffer-strategy", b));
config.getProperty(JsonbConfig.FORMATTING).ifPresent(b -> map.put(JsonGenerator.PRETTY_PRINTING, b));
return map;
}
@@ -453,10 +451,10 @@
if (config == null) {
return map;
}
- config.getProperty(JsonParserFactoryImpl.BUFFER_LENGTH).ifPresent(b -> map.put(JsonParserFactoryImpl.BUFFER_LENGTH, b));
- config.getProperty(JsonParserFactoryImpl.MAX_STRING_LENGTH).ifPresent(b -> map.put(JsonParserFactoryImpl.MAX_STRING_LENGTH, b));
- config.getProperty(JsonParserFactoryImpl.SUPPORTS_COMMENTS).ifPresent(b -> map.put(JsonParserFactoryImpl.SUPPORTS_COMMENTS, b));
- config.getProperty(AbstractJsonFactory.BUFFER_STRATEGY).ifPresent(b -> map.put(AbstractJsonFactory.BUFFER_STRATEGY, b));
+ config.getProperty("org.apache.johnzon.default-char-buffer").ifPresent(b -> map.put("org.apache.johnzon.default-char-buffer", b));
+ config.getProperty("org.apache.johnzon.max-string-length").ifPresent(b -> map.put("org.apache.johnzon.max-string-length", b));
+ config.getProperty("org.apache.johnzon.supports-comments").ifPresent(b -> map.put("org.apache.johnzon.supports-comments", b));
+ config.getProperty("org.apache.johnzon.buffer-strategy").ifPresent(b -> map.put("org.apache.johnzon.buffer-strategy", b));
return map;
}
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
index fbcb4a8..a0d0d8c 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -18,7 +18,6 @@
*/
package org.apache.johnzon.jsonb;
-import org.apache.johnzon.core.Types;
import org.apache.johnzon.jsonb.converter.JohnzonJsonbAdapter;
import org.apache.johnzon.jsonb.converter.JsonbDateConverter;
import org.apache.johnzon.jsonb.converter.JsonbLocalDateConverter;
@@ -29,6 +28,7 @@
import org.apache.johnzon.jsonb.converter.JsonbZonedDateTimeConverter;
import org.apache.johnzon.jsonb.order.PerHierarchyAndLexicographicalOrderFieldComparator;
import org.apache.johnzon.jsonb.reflect.GenericArrayTypeImpl;
+import org.apache.johnzon.jsonb.reflect.Types;
import org.apache.johnzon.jsonb.serializer.JohnzonDeserializationContext;
import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext;
import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory;
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/reflect/Types.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/reflect/Types.java
new file mode 100644
index 0000000..09775ce
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/reflect/Types.java
@@ -0,0 +1,157 @@
+/*
+ * 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.jsonb.reflect;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+
+// forked from johnzon-core to ensure the independency without creating a new module just for that
+public class Types {
+ public ParameterizedType findParameterizedType(final Class<?> klass, final Class<?> parameterizedClass) {
+ return new ParameterizedTypeImpl(parameterizedClass, resolveArgumentTypes(klass, parameterizedClass));
+ }
+
+ public Class<?> findParamType(final ParameterizedType type, final Class<?> expectedWrapper) {
+ if (type.getActualTypeArguments().length != 1) {
+ return null;
+ }
+ final Class<?> asClass = asClass(type.getRawType());
+ if (asClass == null || !expectedWrapper.isAssignableFrom(asClass)) {
+ return null;
+ }
+ return asClass(type.getActualTypeArguments()[0]);
+ }
+
+ public Class<?> asClass(final Type type) {
+ return Class.class.isInstance(type) ? Class.class.cast(type) : null;
+ }
+
+ private Type[] resolveArgumentTypes(final Type type, final Class<?> parameterizedClass) {
+ if (type instanceof Class<?>) {
+ return resolveArgumentTypes((Class<?>) type, parameterizedClass);
+ }
+ if (type instanceof ParameterizedType) {
+ return resolveArgumentTypes((ParameterizedType) type, parameterizedClass);
+ }
+ throw new IllegalArgumentException("Cannot resolve argument types from " + type.getClass().getSimpleName());
+ }
+
+ private Type[] resolveArgumentTypes(final Class<?> type, final Class<?> parameterizedClass) {
+ if (parameterizedClass.equals(type)) {
+ // May return Class[] instead of Type[], so copy it as a Type[] to avoid
+ // problems in visit(ParameterizedType)
+ return Arrays.copyOf(type.getTypeParameters(), parameterizedClass.getTypeParameters().length, Type[].class);
+ }
+ if (type.getSuperclass() != null && parameterizedClass.isAssignableFrom(type.getSuperclass())) {
+ return resolveArgumentTypes(type.getGenericSuperclass(), parameterizedClass);
+ }
+ Class<?>[] interfaces = type.getInterfaces();
+ Type[] genericInterfaces = type.getGenericInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (parameterizedClass.isAssignableFrom(interfaces[i])) {
+ return resolveArgumentTypes(genericInterfaces[i], parameterizedClass);
+ }
+ }
+ throw new IllegalArgumentException(String.format("%s is not assignable from %s", type, parameterizedClass));
+ }
+
+ private Type[] resolveArgumentTypes(final ParameterizedType type, final Class<?> parameterizedClass) {
+ final Class<?> rawType = (Class<?>) type.getRawType(); // always a Class
+ final TypeVariable<?>[] typeVariables = rawType.getTypeParameters();
+ final Type[] types = resolveArgumentTypes(rawType, parameterizedClass);
+ for (int i = 0; i < types.length; i++) {
+ if (types[i] instanceof TypeVariable<?>) {
+ TypeVariable<?> typeVariable = (TypeVariable<?>) types[i];
+ for (int j = 0; j < typeVariables.length; j++) {
+ if (typeVariables[j].getName().equals(typeVariable.getName())) {
+ types[i] = type.getActualTypeArguments()[j];
+ }
+ }
+ }
+ }
+ return types;
+ }
+
+ private static class ParameterizedTypeImpl implements ParameterizedType {
+ private final Type rawType;
+ private final Type[] arguments;
+
+ private ParameterizedTypeImpl(final Type rawType, final Type... arguments) {
+ this.rawType = rawType;
+ this.arguments = arguments;
+ }
+
+ @Override
+ public Type getRawType() {
+ return rawType;
+ }
+
+ @Override
+ public Type getOwnerType() {
+ return null;
+ }
+
+ @Override
+ public Type[] getActualTypeArguments() {
+ return arguments;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(arguments) ^ (rawType == null ? 0 : rawType.hashCode());
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ParameterizedType) {
+ final ParameterizedType that = (ParameterizedType) obj;
+ final Type thatRawType = that.getRawType();
+ return that.getOwnerType() == null
+ && (rawType == null ? thatRawType == null : rawType.equals(thatRawType))
+ && Arrays.equals(arguments, that.getActualTypeArguments());
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder buffer = new StringBuilder();
+ buffer.append(((Class<?>) rawType).getSimpleName());
+ final Type[] actualTypes = getActualTypeArguments();
+ if (actualTypes.length > 0) {
+ buffer.append("<");
+ int length = actualTypes.length;
+ for (int i = 0; i < length; i++) {
+ buffer.append(actualTypes[i].toString());
+ if (i != actualTypes.length - 1) {
+ buffer.append(",");
+ }
+ }
+
+ buffer.append(">");
+ }
+ return buffer.toString();
+ }
+ }
+}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonCores.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonCores.java
index 91e0e2d..76a0e35 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonCores.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonCores.java
@@ -18,14 +18,15 @@
*/
package org.apache.johnzon.mapper;
-import static java.util.Optional.ofNullable;
-
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonValue;
+import javax.json.stream.JsonGeneratorFactory;
+import javax.json.stream.JsonParser;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import javax.json.JsonReader;
-import javax.json.JsonReaderFactory;
-import javax.json.stream.JsonParser;
+import static java.util.Optional.ofNullable;
public final class JohnzonCores {
private static final Method CREATE_READER;
@@ -50,7 +51,17 @@
// no-op
}
+ public static SnippetFactory snippetFactory(final int max, final JsonGeneratorFactory factory) {
+ if (CREATE_READER == null) {
+ return JsonValue::toString;
+ }
+ return Snippets.of(max, factory);
+ }
+
public static JsonReader map(final JsonParser parser, final JsonReaderFactory readerFactory) {
+ if (CREATE_READER == null) {
+ throw new IllegalStateException("Ensure to use johnzon-core as JSON-P provider for johnzon-mapper");
+ }
try {
return JsonReader.class.cast(CREATE_READER.invoke(readerFactory, parser));
} catch (final IllegalAccessException e) {
@@ -59,4 +70,15 @@
throw new IllegalStateException(e.getTargetException());
}
}
+
+ // indirection (for classloading)
+ private static class Snippets {
+ private Snippets() {
+ // no-op
+ }
+
+ private static SnippetFactory of(final int max, final JsonGeneratorFactory factory) {
+ return new org.apache.johnzon.core.Snippet(max, factory)::of;
+ }
+ }
}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonVirtualObject.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonVirtualObject.java
index 6cd1aae..dd8f373 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonVirtualObject.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonVirtualObject.java
@@ -22,8 +22,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
-import org.apache.johnzon.core.Experimental;
-
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -34,7 +32,6 @@
@Target(TYPE)
@Retention(RUNTIME)
@Inherited
-@Experimental
public @interface JohnzonVirtualObject {
/**
* @return the virtual object(s) path.
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index fccb9fd..ef4ca51 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -23,7 +23,6 @@
import static java.util.Locale.ROOT;
// import org.apache.johnzon.core.JsonParserFactoryImpl; // don't depend on core in mapper
-import org.apache.johnzon.core.Snippet;
import org.apache.johnzon.mapper.access.AccessMode;
import org.apache.johnzon.mapper.access.BaseAccessMode;
import org.apache.johnzon.mapper.access.FieldAccessMode;
@@ -130,7 +129,7 @@
config.put("org.apache.johnzon.buffer-strategy", bufferStrategy);
}
if (encoding != null) {
- config.put("org.apache.johnzon.encoding", encoding.name());
+ config.put("org.apache.johnzon.encoding", encoding);
}
if (generatorFactory == null) {
@@ -239,7 +238,7 @@
typeLoader, discriminatorMapper, discriminator,
deserializationPredicate, serializationPredicate,
enumConverterFactory,
- new Snippet(snippetMaxLength, generatorFactory)),
+ JohnzonCores.snippetFactory(snippetMaxLength, generatorFactory)),
closeables);
}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
index eb8affc..824c670 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
@@ -18,7 +18,6 @@
*/
package org.apache.johnzon.mapper;
-import org.apache.johnzon.core.Snippet;
import org.apache.johnzon.mapper.access.AccessMode;
import org.apache.johnzon.mapper.internal.AdapterKey;
import org.apache.johnzon.mapper.internal.ConverterAdapter;
@@ -97,7 +96,7 @@
private final Function<Class<?>, CustomEnumConverter<?>> enumConverterFactory;
- private final Snippet snippet;
+ private final SnippetFactory snippet;
//CHECKSTYLE:OFF
@Deprecated
@@ -130,7 +129,7 @@
attributeOrder, failOnUnknown, serializeValueFilter, useBigDecimalForFloats, deduplicateObjects, interfaceImplementationMapping,
useJsRange, useBigDecimalForObjectNumbers, supportEnumMapDeserialization, typeLoader,
discriminatorMapper, discriminator, deserializationPredicate, serializationPredicate, enumConverterFactory,
- new Snippet(50, Json.createGeneratorFactory(emptyMap())));
+ JohnzonCores.snippetFactory(50, Json.createGeneratorFactory(emptyMap())));
}
//disable checkstyle for 10+ parameters
@@ -158,7 +157,7 @@
final Predicate<Class<?>> deserializationPredicate,
final Predicate<Class<?>> serializationPredicate,
final Function<Class<?>, CustomEnumConverter<?>> enumConverterFactory,
- final Snippet snippet) {
+ final SnippetFactory snippet) {
//CHECKSTYLE:ON
this.objectConverterWriters = objectConverterWriters;
this.objectConverterReaders = objectConverterReaders;
@@ -199,7 +198,7 @@
this.snippet = snippet;
}
- public Snippet getSnippet() {
+ public SnippetFactory getSnippet() {
return snippet;
}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SnippetFactory.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SnippetFactory.java
new file mode 100644
index 0000000..a4d057a
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SnippetFactory.java
@@ -0,0 +1,25 @@
+/*
+ * 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.mapper;
+
+import javax.json.JsonValue;
+
+public interface SnippetFactory {
+ String of(JsonValue value);
+}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
index fe376c0..c6d3495 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
@@ -18,21 +18,14 @@
*/
package org.apache.johnzon.mapper.internal;
-import org.apache.johnzon.core.JsonPointerUtil;
-
/**
* Internal class to easily collect information about the 'depth' of a json object
* without having to eagerly construct it.
- *
+ * <p>
* For use in recursive generator and parser method calls to defer string operations.
*/
public class JsonPointerTracker {
- public static final JsonPointerTracker ROOT = new JsonPointerTracker(null, null) {
- @Override
- public String toString() {
- return "/";
- }
- };
+ public static final JsonPointerTracker ROOT = new JsonPointerTracker(null, null);
private final JsonPointerTracker parent;
private final String currentNode;
@@ -41,7 +34,7 @@
/**
- * @param parent or {@code null} if this is the root object
+ * @param parent or {@code null} if this is the root object
* @param currentNode the name of the attribute or "/" for the root object
*/
public JsonPointerTracker(JsonPointerTracker parent, String currentNode) {
@@ -51,28 +44,44 @@
/**
* For Arrays and Lists.
+ *
* @param jsonPointer
- * @param i current counter number
+ * @param i current counter number
*/
public JsonPointerTracker(JsonPointerTracker jsonPointer, int i) {
- this(jsonPointer, Integer.toString(i));
+ this(jsonPointer, Integer.toString(i));
}
@Override
public String toString() {
- if (jsonPointer == null) {
- if (parent != null) {
- jsonPointer = (parent != ROOT ? parent + "/" : "/") + JsonPointerUtil.encode(currentNode);
- } else {
- if (currentNode != null) {
- jsonPointer = "/" + JsonPointerUtil.encode(currentNode);
- } else {
- jsonPointer = "/";
- }
- }
+ if (jsonPointer != null) {
+ return jsonPointer;
}
-
- return jsonPointer;
+ if (parent != null) {
+ return jsonPointer = (parent != ROOT ? parent + "/" : "/") + encode(currentNode);
+ }
+ if (currentNode != null) {
+ return jsonPointer = "/" + encode(currentNode);
+ }
+ return jsonPointer = "/";
}
+ // from org.apache.johnzon.mapper.internal.JsonPointerTracker to not depend on johnzon-core
+ private static String encode(final String s) {
+ if (s == null || s.isEmpty()) {
+ return s;
+ }
+ return replace(replace(s, "~", "~0"), "/", "~1");
+ }
+
+ private static String replace(final String src, final String from, final String to) {
+ if (src.isEmpty()) {
+ return src;
+ }
+ final int start = src.indexOf(from);
+ if (start >= 0) {
+ return src.substring(0, start) + to + replace(src.substring(start + from.length()), from, to);
+ }
+ return src;
+ }
}