You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@johnzon.apache.org by Romain Manni-Bucau <rm...@apache.org> on 2021/02/04 08:50:14 UTC
Fwd: [johnzon] branch master updated: [JOHNZON-335] workaround for
nested JsonbSerializers handling and invalid JSON
Hi everyone,
If you are using advanced serializers, can you review this.
I tested with the JIRA case and geronimo-openapi but it stays simple cases
and this change is quite impacting when you abuse of ObjectWriter and/or
JsonbSerializers so a second pair of eyes would be great.
---------- Forwarded message ---------
De : <rm...@apache.org>
Date: jeu. 4 févr. 2021 à 09:47
Subject: [johnzon] branch master updated: [JOHNZON-335] workaround for
nested JsonbSerializers handling and invalid JSON
To: commits@johnzon.apache.org <co...@johnzon.apache.org>
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 1e7c5fd [JOHNZON-335] workaround for nested JsonbSerializers
handling and invalid JSON
1e7c5fd is described below
commit 1e7c5fda86789f78a98b21dfecacb826854819e0
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Thu Feb 4 09:46:20 2021 +0100
[JOHNZON-335] workaround for nested JsonbSerializers handling and
invalid JSON
---
.../org/apache/johnzon/core/JsonGeneratorImpl.java | 2 +-
.../org/apache/johnzon/jsonb/SerializerTest.java | 33 +++
.../johnzon/mapper/DynamicMappingGenerator.java | 232
++++++++++++++++++++-
.../johnzon/mapper/MappingGeneratorImpl.java | 6 +-
4 files changed, 265 insertions(+), 8 deletions(-)
diff --git
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorImpl.java
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorImpl.java
index 852aa2e..7520243 100644
---
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorImpl.java
+++
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorImpl.java
@@ -463,7 +463,7 @@ class JsonGeneratorImpl implements JsonGenerator,
JsonChars, Serializable {
JsonGenerationException ex = null;
final GeneratorState state = currentState();
if (state != GeneratorState.END && state !=
GeneratorState.ROOT_VALUE) {
- ex = new JsonGenerationException("Invalid json");
+ ex = new JsonGenerationException("Invalid json, state=" +
state);
}
try {
if (ex == null) {
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 fe658d5..8a7d86b 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
@@ -55,6 +55,12 @@ public class SerializerTest {
public final JsonbRule jsonb = new JsonbRule()
.withPropertyOrderStrategy(PropertyOrderStrategy.LEXICOGRAPHICAL);
+ @Test // https://issues.apache.org/jira/browse/JOHNZON-335
+ public void testNestedSerializer() {
+ final String s = jsonb.toJson(new OuterTestModel());
+ assertEquals("{\"foo\":\"generated in outer
serializer\",\"inner\":{\"bar\":\"generated in inner serializer\"}}", s);
+ }
+
@Test
public void passthroughSerializer() {
final NameHolder nameHolder = new NameHolder();
@@ -770,4 +776,31 @@ public class SerializerTest {
this.student = student;
}
}
+
+ @JsonbTypeSerializer(OuterTestSerializer.class)
+ public static class OuterTestModel {
+ }
+
+ @JsonbTypeSerializer(InnerTestSerializer.class)
+ public static class InnerTestModel {
+ }
+
+ public static class OuterTestSerializer implements
JsonbSerializer<OuterTestModel> {
+ @Override
+ public void serialize(final OuterTestModel obj, final
JsonGenerator generator, final SerializationContext ctx) {
+ generator.writeStartObject();
+ generator.write("foo", "generated in outer serializer");
+ ctx.serialize("inner", new InnerTestModel(), generator);
+ generator.writeEnd();
+ }
+ }
+
+ public static class InnerTestSerializer implements
JsonbSerializer<InnerTestModel> {
+ @Override
+ public void serialize(final InnerTestModel obj, final
JsonGenerator generator, final SerializationContext ctx) {
+ generator.writeStartObject();
+ generator.write("bar", "generated in inner serializer");
+ generator.writeEnd();
+ }
+ }
}
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
index 35c6c2e..e1f6f0e 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/DynamicMappingGenerator.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/DynamicMappingGenerator.java
@@ -18,11 +18,10 @@
*/
package org.apache.johnzon.mapper;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
import javax.json.JsonValue;
import javax.json.stream.JsonGenerator;
+import java.math.BigDecimal;
+import java.math.BigInteger;
public class DynamicMappingGenerator implements MappingGenerator {
private final MappingGenerator delegate;
@@ -30,7 +29,7 @@ public class DynamicMappingGenerator implements
MappingGenerator {
private final Runnable writeEnd;
private final String keyName;
- private InObjectOrPrimitiveJsonGenerator generator;
+ protected InObjectOrPrimitiveJsonGenerator generator;
public DynamicMappingGenerator(final MappingGenerator delegate,
final Runnable writeStart,
@@ -42,10 +41,14 @@ public class DynamicMappingGenerator implements
MappingGenerator {
this.keyName = keyName;
}
+ protected JsonGenerator getRawJsonGenerator() {
+ return delegate.getJsonGenerator();
+ }
+
@Override
public JsonGenerator getJsonGenerator() {
return generator == null ? generator = new
InObjectOrPrimitiveJsonGenerator(
- delegate.getJsonGenerator(), writeStart, keyName) :
generator;
+ getRawJsonGenerator(), writeStart, keyName) : generator;
}
@Override
@@ -61,10 +64,15 @@ public class DynamicMappingGenerator implements
MappingGenerator {
private JsonGenerator ensureGenerator(final JsonGenerator generator) {
if (this.generator != null && this.generator != generator &&
this.generator.delegate != generator) {
this.generator = null;
+ reset();
}
return getJsonGenerator(); // ensure we wrap it
}
+ protected void reset() {
+ // no-op
+ }
+
public void flushIfNeeded() {
if (this.generator.state == WritingState.WROTE_START) {
writeEnd.run();
@@ -342,4 +350,218 @@ public class DynamicMappingGenerator implements
MappingGenerator {
delegate.flush();
}
}
+
+ private static abstract class DelegatingGenerator implements
JsonGenerator {
+ protected final JsonGenerator delegate;
+
+ protected DelegatingGenerator(final JsonGenerator generator) {
+ this.delegate = generator;
+ }
+
+ @Override
+ public JsonGenerator writeKey(final String name) {
+ delegate.writeKey(name);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final JsonValue
value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final String value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final BigInteger
value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final BigDecimal
value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final int value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final long value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final double value) {
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String name, final boolean value)
{
+ delegate.write(name, value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeNull(final String name) {
+ delegate.writeNull(name);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final JsonValue value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final String value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final BigDecimal value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final BigInteger value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final int value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final long value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(final double value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(boolean value) {
+ delegate.write(value);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeNull() {
+ delegate.writeNull();
+ return this;
+ }
+
+ @Override
+ public void close() {
+ delegate.close();
+ }
+
+ @Override
+ public void flush() {
+ delegate.flush();
+ }
+ }
+
+ private static class SkipLastWriteEndGenerator extends
DelegatingGenerator {
+ private int level = -1;
+
+ private SkipLastWriteEndGenerator(final JsonGenerator generator) {
+ super(generator);
+ }
+
+ @Override
+ public JsonGenerator writeStartObject() {
+ level++;
+ if (level > 0) {
+ delegate.writeStartObject();
+ }
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartObject(final String name) {
+ level++;
+ if (level == 0) {
+ level++; // force a writeEnd since it will be a nested
object and not the object we are writing
+ }
+ delegate.writeStartObject(name);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartArray() {
+ level++;
+ delegate.writeStartArray();
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartArray(final String name) {
+ delegate.writeStartArray(name);
+ level++;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeEnd() {
+ if (level > 0) {
+ delegate.writeEnd();
+ }
+ level--;
+ return this;
+ }
+ }
+
+ public static class SkipEnclosingWriteEnd extends
DynamicMappingGenerator {
+ private static final Runnable NOOP = () -> {
+ };
+ private final JsonGenerator rawGenerator;
+
+ private SkipLastWriteEndGenerator skippingGenerator;
+
+ public SkipEnclosingWriteEnd(final MappingGenerator delegate,
final String keyName, final JsonGenerator generator) {
+ super(delegate, NOOP, NOOP, keyName);
+ this.rawGenerator = generator;
+ }
+
+ @Override
+ protected JsonGenerator getRawJsonGenerator() {
+ return rawGenerator;
+ }
+
+ @Override
+ public JsonGenerator getJsonGenerator() {
+ if (skippingGenerator == null) {
+ skippingGenerator = new
SkipLastWriteEndGenerator(super.getJsonGenerator());
+ }
+ return skippingGenerator;
+ }
+
+ @Override
+ protected void reset() {
+ super.reset();
+ skippingGenerator = null;
+ }
+ }
}
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 0a4ec42..b038f9d 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
@@ -45,7 +45,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
private final MapperConfig config;
private final JsonGenerator generator;
private final Mappings mappings;
-
+
private final Boolean isDeduplicateObjects;
private Map<Object, String> jsonPointers;
@@ -348,7 +348,9 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
if (classMapping.writer != null) {
- classMapping.writer.writeJson(object, this);
+ final DynamicMappingGenerator gen = new
DynamicMappingGenerator.SkipEnclosingWriteEnd(this, null, generator);
+ classMapping.writer.writeJson(object, gen);
+ gen.flushIfNeeded();
return;
}
if (classMapping.adapter != null) {