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/03/03 16:05:31 UTC
[johnzon] branch master updated: JOHNZON-203 first round of impl
for JsonValue <-> pojo binding bypassing IO steps
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 f28196b JOHNZON-203 first round of impl for JsonValue <-> pojo binding bypassing IO steps
f28196b is described below
commit f28196b39ae3d0ff2ccdd8b1e9efe2a5801e1e7f
Author: Romain Manni-Bucau <rm...@apache.org>
AuthorDate: Sun Mar 3 17:05:20 2019 +0100
JOHNZON-203 first round of impl for JsonValue <-> pojo binding bypassing IO steps
---
.../org/apache/johnzon/jsonb/JohnzonJsonb.java | 20 ++
.../johnzon/jsonb/extension/JsonValueReader.java | 54 ++++
.../johnzon/jsonb/extension/JsonValueWriter.java | 60 +++++
.../apache/johnzon/jsonb/JsonbJsonValueTest.java | 57 ++++
.../apache/johnzon/mapper/JsonObjectGenerator.java | 291 +++++++++++++++++++++
.../java/org/apache/johnzon/mapper/Mapper.java | 109 +++++++-
.../org/apache/johnzon/mapper/MapperBuilder.java | 27 +-
.../java/org/apache/johnzon/mapper/MapperTest.java | 46 ++++
.../java/org/superbiz/MultiStructureObject.java | 34 +++
src/site/markdown/index.md | 21 +-
10 files changed, 702 insertions(+), 17 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 9894228..644a5f1 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
@@ -18,6 +18,8 @@
*/
package org.apache.johnzon.jsonb;
+import org.apache.johnzon.jsonb.extension.JsonValueReader;
+import org.apache.johnzon.jsonb.extension.JsonValueWriter;
import org.apache.johnzon.mapper.Mapper;
import org.apache.johnzon.mapper.MapperException;
import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
@@ -124,6 +126,10 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable {
@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);
+ }
+
try {
if (isArray(type)) {
return delegate.readTypedArray(reader, type.getComponentType(), type);
@@ -143,6 +149,10 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable {
@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);
+ }
+
try {
if (isArray(runtimeType)) {
final Class<T> type = Class.class.cast(runtimeType);
@@ -284,6 +294,11 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable {
@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));
+ return;
+ }
+
final Object object = unwrapOptional(inObject);
if (object != null && isArray(object.getClass())) {
delegate.writeArray((Object[]) object, writer);
@@ -296,6 +311,11 @@ public class JohnzonJsonb implements Jsonb, AutoCloseable {
@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));
+ return;
+ }
+
final Object object = unwrapOptional(inObject);
if (object != null && isArray(runtimeType)) {
delegate.writeArray((Object[]) object, writer);
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
new file mode 100644
index 0000000..222a6e0
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueReader.java
@@ -0,0 +1,54 @@
+/*
+ * 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.extension;
+
+import java.io.Reader;
+
+import javax.json.JsonStructure;
+
+public class JsonValueReader<T> extends Reader {
+ private final JsonStructure input;
+ private T result;
+
+ public JsonValueReader(final JsonStructure input) {
+ this.input = input;
+ }
+
+ @Override
+ public int read(final char[] cbuf, final int off, final int len) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close() {
+ // no-op
+ }
+
+ public JsonStructure getInput() {
+ return input;
+ }
+
+ public T getResult() {
+ return result;
+ }
+
+ 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
new file mode 100644
index 0000000..a861658
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/extension/JsonValueWriter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.extension;
+
+import java.io.Writer;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
+
+public class JsonValueWriter extends Writer {
+ private JsonValue result;
+
+ @Override
+ public void write(final char[] cbuf, final int off, final int len) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void flush() {
+ // no-op
+ }
+
+ @Override
+ public void close() {
+ flush();
+ }
+
+ public void setResult(final JsonValue result) {
+ this.result = result;
+ }
+
+ public JsonValue getResult() {
+ return result;
+ }
+
+ public JsonObject getObject() {
+ return result.asJsonObject();
+ }
+
+ public JsonArray getArray() {
+ return result.asJsonArray();
+ }
+}
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbJsonValueTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbJsonValueTest.java
new file mode 100644
index 0000000..a21f28a
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbJsonValueTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbBuilder;
+
+import org.apache.johnzon.jsonb.extension.JsonValueReader;
+import org.apache.johnzon.jsonb.extension.JsonValueWriter;
+import org.junit.Test;
+
+public class JsonbJsonValueTest {
+ @Test
+ public void from() throws Exception {
+ final JsonValueReader<Simple> reader = new JsonValueReader<>(Json.createObjectBuilder().add("value", "simple").build());
+ final Jsonb jsonb = JsonbBuilder.create();
+ final Simple simple = jsonb.fromJson(reader, Simple.class);
+ jsonb.close();
+ assertEquals("simple", simple.value);
+ }
+
+ @Test
+ public void to() throws Exception {
+ final Simple object = new Simple();
+ object.value = "simple";
+ final JsonValueWriter writer = new JsonValueWriter();
+ final Jsonb jsonb = JsonbBuilder.create();
+ jsonb.toJson(object, writer);
+ jsonb.close();
+ final JsonObject jsonObject = writer.getObject();
+ assertEquals("{\"value\":\"simple\"}", jsonObject.toString());
+ }
+
+ public static class Simple {
+ public String value;
+ }
+}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JsonObjectGenerator.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JsonObjectGenerator.java
new file mode 100644
index 0000000..9f8b380
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JsonObjectGenerator.java
@@ -0,0 +1,291 @@
+/*
+ * 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 java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.LinkedList;
+
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+
+// assume usage is right, since it is an internal based on the fact we correctly use jsongenerator api it is fine
+// todo: drop reflection, it is not needed here but it was simpler for a first impl
+public class JsonObjectGenerator implements JsonGenerator {
+ private final JsonBuilderFactory factory;
+ private final LinkedList<Object> builders = new LinkedList<>();
+
+ private JsonObjectBuilder objectBuilder;
+ private JsonArrayBuilder arrayBuilder;
+
+ public JsonObjectGenerator(final JsonBuilderFactory factory) {
+ this.factory = factory;
+ }
+
+ @Override
+ public JsonGenerator writeStartObject() {
+ objectBuilder = factory.createObjectBuilder();
+ builders.add(objectBuilder);
+ arrayBuilder = null;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartObject(final String name) {
+ objectBuilder = factory.createObjectBuilder();
+ builders.add(new NamedBuilder<>(objectBuilder, name));
+ arrayBuilder = null;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartArray() {
+ arrayBuilder = factory.createArrayBuilder();
+ builders.add(arrayBuilder);
+ objectBuilder = null;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartArray(final String name) {
+ arrayBuilder = factory.createArrayBuilder();
+ builders.add(new NamedBuilder<>(arrayBuilder, name));
+ objectBuilder = null;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeKey(final String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final JsonValue value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final String value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final BigInteger value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final BigDecimal value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final int value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final long value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final double value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final boolean value) {
+ objectBuilder.add(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeNull(final String name) {
+ objectBuilder.addNull(name);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final JsonValue value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final BigDecimal value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final BigInteger value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final int value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final long value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final double value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final boolean value) {
+ arrayBuilder.add(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeNull() {
+ arrayBuilder.addNull();
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeEnd() {
+ if (builders.size() == 1) {
+ return this;
+ }
+
+ final Object last = builders.removeLast();
+
+ /*
+ * Previous potential cases:
+ * 1. json array -> we add the builder directly
+ * 2. NamedBuilder{array|object} -> we add the builder in the previous object
+ */
+
+ final String name;
+ Object previous = builders.getLast();
+ if (NamedBuilder.class.isInstance(previous)) {
+ final NamedBuilder namedBuilder = NamedBuilder.class.cast(previous);
+ name = namedBuilder.name;
+ previous = namedBuilder.builder;
+ } else {
+ name = null;
+ }
+
+ if (JsonArrayBuilder.class.isInstance(last)) {
+ final JsonArrayBuilder array = JsonArrayBuilder.class.cast(last);
+ if (JsonArrayBuilder.class.isInstance(previous)) {
+ arrayBuilder = JsonArrayBuilder.class.cast(previous);
+ objectBuilder = null;
+ arrayBuilder.add(array);
+ } else if (JsonObjectBuilder.class.isInstance(previous)) {
+ objectBuilder = JsonObjectBuilder.class.cast(previous);
+ arrayBuilder = null;
+ objectBuilder.add(name, array);
+ } else {
+ throw new IllegalArgumentException("Unsupported previous builder: " + previous);
+ }
+ } else if (JsonObjectBuilder.class.isInstance(last)) {
+ final JsonObjectBuilder object = JsonObjectBuilder.class.cast(last);
+ if (JsonArrayBuilder.class.isInstance(previous)) {
+ arrayBuilder = JsonArrayBuilder.class.cast(previous);
+ objectBuilder = null;
+ arrayBuilder.add(object);
+ } else if (JsonObjectBuilder.class.isInstance(previous)) {
+ objectBuilder = JsonObjectBuilder.class.cast(previous);
+ arrayBuilder = null;
+ objectBuilder.add(name, object);
+ } else {
+ throw new IllegalArgumentException("Unsupported previous builder: " + previous);
+ }
+ } else if (NamedBuilder.class.isInstance(last)) {
+ final NamedBuilder<?> namedBuilder = NamedBuilder.class.cast(last);
+ if (JsonObjectBuilder.class.isInstance(previous)) {
+ objectBuilder = JsonObjectBuilder.class.cast(previous);
+ if (JsonArrayBuilder.class.isInstance(namedBuilder.builder)) {
+ objectBuilder.add(namedBuilder.name, JsonArrayBuilder.class.cast(namedBuilder.builder));
+ arrayBuilder = null;
+ } else if (JsonObjectBuilder.class.isInstance(namedBuilder.builder)) {
+ objectBuilder.add(namedBuilder.name, JsonObjectBuilder.class.cast(namedBuilder.builder));
+ arrayBuilder = null;
+ } else {
+ throw new IllegalArgumentException("Unsupported previous builder: " + previous);
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported previous builder, expected object builder: " + previous);
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported previous builder: " + previous);
+ }
+ return this;
+ }
+
+ @Override
+ public void flush() {
+ // no-op
+ }
+
+ @Override
+ public void close() {
+ flush();
+ }
+
+ public JsonValue getResult() {
+ final Object last = builders.getLast();
+ if (JsonArrayBuilder.class.isInstance(last)) {
+ return JsonArrayBuilder.class.cast(last).build();
+ }
+ if (JsonObjectBuilder.class.isInstance(last)) {
+ return JsonObjectBuilder.class.cast(last).build();
+ }
+ throw new IllegalArgumentException("Nothing prepared or wrongly prepared");
+ }
+
+ private static class NamedBuilder<T> {
+ private final T builder;
+ private final String name;
+
+ private NamedBuilder(final T builder, final String name) {
+ this.builder = builder;
+ this.name = name;
+ }
+ }
+}
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 da28ae7..77b22b6 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
@@ -18,14 +18,9 @@
*/
package org.apache.johnzon.mapper;
-import org.apache.johnzon.mapper.internal.JsonPointerTracker;
-import org.apache.johnzon.mapper.reflection.JohnzonCollectionType;
+import static java.util.Arrays.asList;
+import static org.apache.johnzon.mapper.internal.Streams.noClose;
-import javax.json.JsonReader;
-import javax.json.JsonReaderFactory;
-import javax.json.JsonValue;
-import javax.json.stream.JsonGenerator;
-import javax.json.stream.JsonGeneratorFactory;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
@@ -38,13 +33,26 @@ import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
-import static java.util.Arrays.asList;
-import static org.apache.johnzon.mapper.internal.Streams.noClose;
+import javax.json.JsonArray;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.spi.JsonProvider;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+
+import org.apache.johnzon.mapper.internal.JsonPointerTracker;
+import org.apache.johnzon.mapper.reflection.JohnzonCollectionType;
public class Mapper implements Closeable {
@@ -52,14 +60,19 @@ public class Mapper implements Closeable {
protected final Mappings mappings;
protected final JsonReaderFactory readerFactory;
protected final JsonGeneratorFactory generatorFactory;
+ protected final JsonBuilderFactory builderFactory;
+ protected final JsonProvider provider;
protected final ReaderHandler readerHandler;
protected final Collection<Closeable> closeables;
protected final Charset charset;
- Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory, MapperConfig config,
- final Collection<Closeable> closeables) {
+ Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory,
+ final JsonBuilderFactory builderFactory, final JsonProvider provider,
+ final MapperConfig config, final Collection<Closeable> closeables) {
this.readerFactory = readerFactory;
this.generatorFactory = generatorFactory;
+ this.builderFactory = builderFactory;
+ this.provider = provider;
this.config = config;
this.mappings = new Mappings(config);
this.readerHandler = ReaderHandler.create(readerFactory);
@@ -102,6 +115,43 @@ public class Mapper implements Closeable {
}
}
+ public JsonValue toStructure(final Object object) {
+ if (object == null) {
+ return JsonValue.NULL;
+ }
+ if (JsonStructure.class.isInstance(object)) {
+ return JsonStructure.class.cast(object);
+ }
+ if (Boolean.class.isInstance(object)) {
+ return Boolean.class.cast(object) ? JsonValue.TRUE : JsonValue.FALSE;
+ }
+ if (String.class.isInstance(object)) {
+ return provider.createValue(String.class.cast(object));
+ }
+ if (Double.class.isInstance(object)) {
+ return provider.createValue(Double.class.cast(object));
+ }
+ if (Float.class.isInstance(object)) {
+ return provider.createValue(Float.class.cast(object));
+ }
+ if (Long.class.isInstance(object)) {
+ return provider.createValue(Long.class.cast(object));
+ }
+ if (Integer.class.isInstance(object)) {
+ return provider.createValue(Integer.class.cast(object));
+ }
+ if (BigDecimal.class.isInstance(object)) {
+ return provider.createValue(BigDecimal.class.cast(object));
+ }
+ if (BigInteger.class.isInstance(object)) {
+ return provider.createValue(BigInteger.class.cast(object));
+ }
+ final JsonObjectGenerator objectGenerator = new JsonObjectGenerator(builderFactory);
+ writeObject(object, objectGenerator, null,
+ isDeduplicateObjects(object.getClass()) ? new JsonPointerTracker(null, "/") : null);
+ return objectGenerator.getResult();
+ }
+
public void writeObject(final Object object, final Writer stream) {
if (JsonValue.class.isInstance(object)
|| Boolean.class.isInstance(object) || String.class.isInstance(object) || Number.class.isInstance(object)
@@ -179,6 +229,34 @@ public class Mapper implements Closeable {
return writer.toString();
}
+ public <T> T readObject(final JsonStructure value, final Type clazz) {
+ return new MappingParserImpl(config, mappings, new JsonReader() {
+ @Override
+ public JsonStructure read() {
+ return value;
+ }
+
+ @Override
+ public JsonValue readValue() {
+ return value;
+ }
+
+ @Override
+ public JsonObject readObject() {
+ return value.asJsonObject();
+ }
+
+ @Override
+ public JsonArray readArray() {
+ return value.asJsonArray();
+ }
+
+ @Override
+ public void close() {
+ // no-op
+ }
+ }, isDedup(clazz)).readObject(clazz);
+ }
public <T> T readObject(final String string, final Type clazz) {
return readObject(new StringReader(string), clazz);
@@ -247,11 +325,14 @@ public class Mapper implements Closeable {
private <T> T mapObject(final Type clazz, final JsonReader reader) {
- boolean dedup = false;
+ return new MappingParserImpl(config, mappings, reader, isDedup(clazz)).readObject(clazz);
+ }
+
+ private boolean isDedup(final Type clazz) {
if (clazz instanceof Class) {
- dedup = isDeduplicateObjects((Class) clazz);
+ return isDeduplicateObjects((Class) clazz);
}
- return new MappingParserImpl(config, mappings, reader, dedup).readObject(clazz);
+ return false;
}
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 5d6debb..258ce5f 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
@@ -19,6 +19,7 @@
package org.apache.johnzon.mapper;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptyMap;
import static java.util.Locale.ROOT;
import org.apache.johnzon.core.JsonParserFactoryImpl;
@@ -47,6 +48,7 @@ import org.apache.johnzon.mapper.converter.URLConverter;
import org.apache.johnzon.mapper.internal.AdapterKey;
import org.apache.johnzon.mapper.internal.ConverterAdapter;
+import javax.json.JsonBuilderFactory;
import javax.json.JsonReaderFactory;
import javax.json.spi.JsonProvider;
import javax.json.stream.JsonGenerator;
@@ -106,6 +108,8 @@ public class MapperBuilder {
private JsonReaderFactory readerFactory;
private JsonGeneratorFactory generatorFactory;
+ private JsonProvider provider;
+ private JsonBuilderFactory builderFactory;
private boolean supportHiddenAccess = true;
private int maxSize = -1;
private int bufferSize = -1;
@@ -142,7 +146,13 @@ public class MapperBuilder {
public Mapper build() {
if (readerFactory == null || generatorFactory == null) {
- final JsonProvider provider = JsonProvider.provider();
+ final JsonProvider provider;
+ if (this.provider != null) {
+ provider = this.provider;
+ } else {
+ provider = JsonProvider.provider();
+ this.provider = provider;
+ }
final Map<String, Object> config = new HashMap<String, Object>();
if (bufferStrategy != null) {
config.put(JsonParserFactoryImpl.BUFFER_STRATEGY, bufferStrategy);
@@ -171,6 +181,9 @@ public class MapperBuilder {
if (readerFactory == null) {
readerFactory = provider.createReaderFactory(config);
}
+ if (builderFactory == null) {
+ builderFactory = provider.createBuilderFactory(emptyMap());
+ }
}
if (accessMode == null) {
@@ -233,7 +246,7 @@ public class MapperBuilder {
}
return new Mapper(
- readerFactory, generatorFactory,
+ readerFactory, generatorFactory, builderFactory, provider,
new MapperConfig(
adapters, objectConverterWriters, objectConverterReaders,
version, close,
@@ -345,6 +358,16 @@ public class MapperBuilder {
return this;
}
+ public MapperBuilder setProvider(final JsonProvider provider) {
+ this.provider = provider;
+ return this;
+ }
+
+ public MapperBuilder setBuilderFactory(final JsonBuilderFactory builderFactory) {
+ this.builderFactory = builderFactory;
+ return this;
+ }
+
public MapperBuilder setDoCloseOnStreams(final boolean doCloseOnStreams) {
this.close = doCloseOnStreams;
return this;
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
index 3e7672e..912fbb2 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
@@ -23,6 +23,7 @@ import org.apache.johnzon.mapper.reflection.JohnzonCollectionType;
import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
import org.junit.Assert;
import org.junit.Test;
+import org.superbiz.MultiStructureObject;
import java.beans.ConstructorProperties;
import java.io.ByteArrayInputStream;
@@ -53,6 +54,10 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
+
public class MapperTest {
private static final String BIG_OBJECT_STR = "{" + "\"name\":\"the string\"," + "\"intVal\":56," + "\"longnumber\":118,"
+ "\"bool\":true," + "\"nested\":{" + "\"name\":\"another value\"," + "\"intVal\":97," + "\"longnumber\":34" + "},"
@@ -62,6 +67,47 @@ public class MapperTest {
+ "\"primitives\":[1,2,3,4,5]," + "\"collectionWrapper\":[1,2,3,4,5]," + "\"map\":{\"uno\":true,\"duos\":false}" + "}";
@Test
+ public void mapToJsonValue() {
+ final Child object = new Child();
+ object.children = Collections.singletonList("first");
+ object.a = 5;
+ object.b = 6;
+ object.c = 7;
+ final JsonValue structure = new MapperBuilder().build().toStructure(object);
+ assertEquals(JsonValue.ValueType.OBJECT, structure.getValueType());
+ final JsonObject jsonObject = structure.asJsonObject();
+ assertEquals(4, jsonObject.size());
+ assertEquals(5, jsonObject.getInt("a"));
+ assertEquals(6, jsonObject.getInt("b"));
+ assertEquals(7, jsonObject.getInt("c"));
+
+ final JsonArray children = jsonObject.getJsonArray("children");
+ assertEquals(1, children.size());
+ assertEquals("first", children.getString(0));
+ }
+
+ @Test
+ public void mapToJsonValueComplex() {
+ final MultiStructureObject.Nested n1 = new MultiStructureObject.Nested();
+ n1.number = 3;
+
+ final MultiStructureObject object = new MultiStructureObject();
+ object.names = asList("first", "second");
+ object.data = "some";
+ object.polymorphic = new HashMap<>();
+ object.polymorphic.put("a", 1);
+ object.polymorphic.put("b", "2");
+ object.nesteds = Collections.singletonList(n1);
+ object.nestedMap = Collections.singletonMap("n1", n1);
+
+ final JsonValue structure = new MapperBuilder().setAttributeOrder(String.CASE_INSENSITIVE_ORDER).build().toStructure(object);
+ assertEquals(JsonValue.ValueType.OBJECT, structure.getValueType());
+ final JsonObject jsonObject = structure.asJsonObject();
+ assertEquals("{\"data\":\"some\",\"names\":[\"first\",\"second\"],\"nestedMap\":{\"n1\":{\"number\":3}}," +
+ "\"nesteds\":[{\"number\":3}],\"polymorphic\":{\"a\":1,\"b\":\"2\"}}", jsonObject.toString());
+ }
+
+ @Test
public void ignoreAllStrategy() {
final StringWriter writer = new StringWriter();
final Child object = new Child();
diff --git a/johnzon-mapper/src/test/java/org/superbiz/MultiStructureObject.java b/johnzon-mapper/src/test/java/org/superbiz/MultiStructureObject.java
new file mode 100644
index 0000000..3207c43
--- /dev/null
+++ b/johnzon-mapper/src/test/java/org/superbiz/MultiStructureObject.java
@@ -0,0 +1,34 @@
+/*
+ * 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.superbiz;
+
+import java.util.Collection;
+import java.util.Map;
+
+public class MultiStructureObject {
+ public Map<String, Object> polymorphic;
+ public String data;
+ public Collection<Nested> nesteds;
+ public Map<String, Nested> nestedMap;
+ public Collection<String> names;
+
+ public static class Nested {
+ public int number;
+ }
+}
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 7ee99a3..db026f0 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -298,7 +298,26 @@ It fully reuses the JSON-B as API.
However it supports some specific properties to wire to the native johnzon configuration - see `JohnzonBuilder` for details.
One example is `johnzon.interfaceImplementationMapping` which will support a `Map<Class,Class>` to map interfaces to implementations
-to use for deserialization.
+to use for deserialization.
+
+#### Integration with `JsonValue`
+
+You can use some optimization to map a `JsonObject` to a POJO using Johnzon `JsonValueReader` and `JsonValueWriter`:
+
+<pre class="prettyprint linenums"><![CDATA[
+final JsonValueReader<Simple> reader = new JsonValueReader<>(Json.createObjectBuilder().add("value", "simple").build());
+final Jsonb jsonb = getJohnsonJsonb();
+final Simple simple = jsonb.fromJson(reader, SomeModel.class);
+]]></pre>
+
+<pre class="prettyprint linenums"><![CDATA[
+final JsonValueWriter writer = new JsonValueWriter();
+final Jsonb jsonb = getJohnsonJsonb();
+jsonb.toJson(object, writer);
+final JsonObject jsonObject = writer.getObject();
+]]></pre>
+
+These two example will not use any IO and directly map the `JsonValue` to/from a POJO.
### Websocket