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/04/02 13:17:24 UTC
[johnzon] branch master updated: JOHNZON-207 tolerate primitive in
objects in serializers
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 4f73100 JOHNZON-207 tolerate primitive in objects in serializers
4f73100 is described below
commit 4f73100bdb5a094c7f05d361b0753e5bfe031566
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Tue Apr 2 15:17:14 2019 +0200
JOHNZON-207 tolerate primitive in objects in serializers
---
.../org/apache/johnzon/jsonb/JohnzonBuilder.java | 6 +-
.../org/apache/johnzon/jsonb/SerializerTest.java | 38 ++-
.../johnzon/mapper/DynamicMappingGenerator.java | 277 +++++++++++++++++++++
.../johnzon/mapper/MappingGeneratorImpl.java | 37 +--
4 files changed, 334 insertions(+), 24 deletions(-)
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 a12608d..d146d79 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
@@ -284,8 +284,10 @@ public class JohnzonBuilder implements JsonbBuilder {
throw new IllegalArgumentException("We only support serializer on Class for now");
}
builder.addObjectConverter(
- Class.class.cast(args[0]), (ObjectConverter.Writer)
- (instance, jsonbGenerator) -> s.serialize(instance, jsonbGenerator.getJsonGenerator(), new JohnzonSerializationContext(jsonbGenerator)));
+ Class.class.cast(args[0]), (ObjectConverter.Writer) (instance, jsonbGenerator) ->
+ s.serialize(
+ instance, jsonbGenerator.getJsonGenerator(),
+ new JohnzonSerializationContext(jsonbGenerator)));
});
});
config.getProperty(JsonbConfig.DESERIALIZERS).map(JsonbDeserializer[].class::cast).ifPresent(deserializers -> {
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
index 963a41e..030f8fc 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
@@ -18,7 +18,14 @@
*/
package org.apache.johnzon.jsonb;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
@@ -30,13 +37,8 @@ import javax.json.bind.serializer.JsonbSerializer;
import javax.json.bind.serializer.SerializationContext;
import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonParser;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.List;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
public class SerializerTest {
@@ -107,6 +109,15 @@ public class SerializerTest {
assertEquals("{\"elems\":[\"WRONG\",null]}", jsonb.toJson(wrapper));
}
+ @Test
+ public void uuid() throws Exception {
+ final Jsonb jsonb = JsonbBuilder.create();
+ final UUIDWrapper wrapper = new UUIDWrapper();
+ wrapper.uuid = UUID.randomUUID();
+ assertEquals("{\"uuid\":\"4a34a0e8-c0c1-45f7-9fa4-2e28f15fd9be\"}", jsonb.toJson(wrapper));
+ jsonb.close();
+ }
+
public static class Foo {
public String name;
@@ -114,7 +125,20 @@ public class SerializerTest {
public boolean flag;
}
+ public static class UUIDSerializer implements JsonbSerializer<UUID> {
+ @Override
+ public void serialize(final UUID obj, final JsonGenerator generator, final SerializationContext ctx) {
+ generator.write(obj.toString());
+ }
+ }
+
+ public static class UUIDWrapper {
+ @JsonbTypeSerializer(UUIDSerializer.class)
+ public UUID uuid;
+ }
+
public static class Wrapper {
+
@JsonbTypeSerializer(FooSer.class)
@JsonbTypeDeserializer(FooDeser.class)
public Foo foo;
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/DynamicMappingGenerator.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/DynamicMappingGenerator.java
new file mode 100644
index 0000000..fff01e6
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/DynamicMappingGenerator.java
@@ -0,0 +1,277 @@
+/*
+ * 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 javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+
+public class DynamicMappingGenerator implements MappingGenerator {
+ private final MappingGenerator delegate;
+ private final Runnable writeStart;
+ private final Runnable writeEnd;
+ private final String keyName;
+
+ private InObjectOrPrimitiveJsonGenerator generator;
+
+ public DynamicMappingGenerator(final MappingGenerator delegate,
+ final Runnable writeStart,
+ final Runnable writeEnd,
+ final String keyName) {
+ this.delegate = delegate;
+ this.writeStart = writeStart;
+ this.writeEnd = writeEnd;
+ this.keyName = keyName;
+ }
+
+ @Override
+ public JsonGenerator getJsonGenerator() {
+ return generator == null ? generator = new InObjectOrPrimitiveJsonGenerator(
+ delegate.getJsonGenerator(), writeStart, keyName) : generator;
+ }
+
+ @Override
+ public MappingGenerator writeObject(final Object o, final JsonGenerator generator) {
+ if (this.generator != null && this.generator != generator && this.generator.delegate != generator) {
+ this.generator = null;
+ }
+ getJsonGenerator(); // ensure we wrap it
+
+ final MappingGenerator mappingGenerator = delegate.writeObject(o, this.generator);
+ flushIfNeeded();
+ return mappingGenerator;
+ }
+
+ public void flushIfNeeded() {
+ if (this.generator.state == WritingState.WROTE_START_OBJECT) {
+ writeEnd.run();
+ this.generator.state = WritingState.NONE;
+ }
+ }
+
+ private enum WritingState {
+ NONE, WROTE_START_OBJECT, PRIMITIVE
+ }
+
+ private static class InObjectOrPrimitiveJsonGenerator implements JsonGenerator {
+ private final JsonGenerator delegate;
+ private final Runnable writeStart;
+ private final String keyIfNoObject;
+ private WritingState state = WritingState.NONE;
+
+ private InObjectOrPrimitiveJsonGenerator(final JsonGenerator generator, final Runnable writeStart,
+ final String keyName) {
+ this.delegate = generator;
+ this.writeStart = writeStart;
+ this.keyIfNoObject = keyName;
+ }
+
+ private void ensureStart() {
+ if (state == WritingState.WROTE_START_OBJECT) {
+ return;
+ }
+ writeStart.run();
+ state = WritingState.WROTE_START_OBJECT;
+ }
+
+ @Override
+ public JsonGenerator writeStartObject() {
+ return delegate.writeStartObject();
+ }
+
+ @Override
+ public JsonGenerator writeStartObject(final String name) {
+ ensureStart();
+ return delegate.writeStartObject(name);
+ }
+
+ @Override
+ public JsonGenerator writeStartArray() {
+ return delegate.writeStartArray();
+ }
+
+ @Override
+ public JsonGenerator writeStartArray(final String name) {
+ ensureStart();
+ return delegate.writeStartArray(name);
+ }
+
+ @Override
+ public JsonGenerator writeKey(final String name) {
+ ensureStart();
+ return delegate.writeKey(name);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final JsonValue value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final String value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final BigInteger value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final BigDecimal value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final int value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final long value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final double value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final boolean value) {
+ ensureStart();
+ return delegate.write(name, value);
+ }
+
+ @Override
+ public JsonGenerator writeNull(final String name) {
+ ensureStart();
+ return delegate.writeNull(name);
+ }
+
+ @Override
+ public JsonGenerator writeEnd() {
+ return delegate.writeEnd();
+ }
+
+ @Override
+ public JsonGenerator write(final JsonValue value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(final String value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(final BigDecimal value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(final BigInteger value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(final int value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(final long value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(final double value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator write(boolean value) {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.write(keyIfNoObject, value);
+ }
+ return delegate.write(value);
+ }
+
+ @Override
+ public JsonGenerator writeNull() {
+ if (isWritingPrimitive()) {
+ state = WritingState.PRIMITIVE;
+ return delegate.writeNull(keyIfNoObject);
+ }
+ return delegate.writeNull();
+ }
+
+ private boolean isWritingPrimitive() {
+ return state == WritingState.NONE && keyIfNoObject != null;
+ }
+
+ @Override
+ public void close() {
+ delegate.close();
+ }
+
+ @Override
+ public void flush() {
+ delegate.flush();
+ }
+ }
+}
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index d35a580..5c17a4f 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
@@ -105,19 +105,24 @@ public class MappingGeneratorImpl implements MappingGenerator {
return;
}
- if (writeBody) {
- generator.writeStartObject();
- }
-
ObjectConverter.Writer objectConverter = config.findObjectConverterWriter(objectClass);
if (writeBody && objectConverter != null) {
- objectConverter.writeJson(object, this);
+ if (!writeBody) {
+ objectConverter.writeJson(object, this);
+ } else {
+ final DynamicMappingGenerator dynamicMappingGenerator = new DynamicMappingGenerator(this,
+ generator::writeStartObject, generator::writeEnd, null);
+ objectConverter.writeJson(object, dynamicMappingGenerator);
+ dynamicMappingGenerator.flushIfNeeded();
+ }
} else {
+ if (writeBody) {
+ generator.writeStartObject();
+ }
doWriteObjectBody(object, ignoredProperties, jsonPointer);
- }
-
- if (writeBody) {
- generator.writeEnd();
+ if (writeBody) {
+ generator.writeEnd();
+ }
}
} catch (final InvocationTargetException e) {
throw new MapperException(e);
@@ -344,9 +349,10 @@ public class MappingGeneratorImpl implements MappingGenerator {
}
if (objectConverterToUse != null) {
- generator.writeStartObject();
- objectConverterToUse.writeJson(o, this);
- generator.writeEnd();
+ final DynamicMappingGenerator dynamicMappingGenerator = new DynamicMappingGenerator(this,
+ generator::writeStartObject, generator::writeEnd, null);
+ objectConverterToUse.writeJson(o, dynamicMappingGenerator);
+ dynamicMappingGenerator.flushIfNeeded();
} else {
writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties,
isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, i) : null);
@@ -377,9 +383,10 @@ public class MappingGeneratorImpl implements MappingGenerator {
}
if (objectConverterToUse != null) {
- generator.writeStartObject(key);
- objectConverterToUse.writeJson(value, this);
- generator.writeEnd();
+ final DynamicMappingGenerator generator = new DynamicMappingGenerator(this,
+ () -> this.generator.writeStartObject(key), this.generator::writeEnd, key);
+ objectConverterToUse.writeJson(value, generator);
+ generator.flushIfNeeded();
return;
}
}