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 <rmannibu...@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) {

Reply via email to