This is an automated email from the ASF dual-hosted git repository.
struberg 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 c94db5ee JOHNZON-421 Defer start of object/array
c94db5ee is described below
commit c94db5ee3cd0864fb749e0445b264aa662aaad4b
Author: Mark Struberg <[email protected]>
AuthorDate: Wed Feb 11 15:00:46 2026 +0100
JOHNZON-421 Defer start of object/array
This is necessary as we don't know what Serializers/Adapters/Converters
actually do write.
If we start an object with { and the JsonbSerializer just writes a string
value (json primitive)
then we will blow up. Deferring the start fixes this issue.
---
.../org/apache/johnzon/jsonb/JohnzonBuilder.java | 4 +-
.../org/apache/johnzon/jsonb/JsonbAccessMode.java | 5 +-
.../johnzon/jsonb/JohnzonConverterInJsonbTest.java | 5 +-
.../org/apache/johnzon/jsonb/SerializerTest.java | 2 +-
.../johnzon/jsonb/SerializersRoundTripTest.java | 3 +-
.../SerialiseAsPrimitiveAnnotatedAtClassTest.java | 129 ++++++++
.../johnzon/mapper/DynamicMappingGenerator.java | 43 +--
.../java/org/apache/johnzon/mapper/Mapper.java | 2 +-
.../org/apache/johnzon/mapper/MapperConfig.java | 4 +-
.../apache/johnzon/mapper/MappingGenerator.java | 7 +-
.../johnzon/mapper/MappingGeneratorImpl.java | 120 +++----
.../org/apache/johnzon/mapper/ObjectConverter.java | 3 +-
.../mapper/jsonp/DeferredStartJsonGenerator.java | 354 +++++++++++++++++++++
.../apache/johnzon/mapper/MapperConfigTest.java | 5 +-
.../mapper/ObjectConverterWithAnnotationTest.java | 7 +-
.../org/apache/johnzon/mapper/ObjectTypeTest.java | 11 +-
16 files changed, 582 insertions(+), 122 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 6c8daa0d..460d41c8 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
@@ -321,9 +321,9 @@ 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) ->
+ Class.class.cast(args[0]), (ObjectConverter.Writer)
(instance, jsonbGenerator, generator) ->
s.serialize(
- instance, jsonbGenerator.getJsonGenerator(),
+ instance, generator,
new
JohnzonSerializationContext(jsonbGenerator)));
});
});
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 a18b3481..87f42c75 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
@@ -337,7 +337,7 @@ public class JsonbAccessMode implements AccessMode,
Closeable, Cleanable<Class<?
}
@Override
- public void writeJson(final Object instance,
final MappingGenerator jsonbGenerator) {
+ public void writeJson(final Object instance,
final MappingGenerator jsonbGenerator, JsonGenerator generator) {
// no-op, it's for factories only
}
};
@@ -1183,8 +1183,7 @@ public class JsonbAccessMode implements AccessMode,
Closeable, Cleanable<Class<?
final JsonbSerializer jsonbSerializer = instance.getValue();
writer = new ObjectConverter.Writer() {
@Override
- public void writeJson(final Object instance, final
MappingGenerator jsonbGenerator) {
- final JsonGenerator generator =
jsonbGenerator.getJsonGenerator();
+ public void writeJson(final Object instance, final
MappingGenerator jsonbGenerator, JsonGenerator generator) {
jsonbSerializer.serialize(instance, generator, new
JohnzonSerializationContext(jsonbGenerator));
}
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
index cab88d37..24d64780 100644
---
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
+++
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonConverterInJsonbTest.java
@@ -27,6 +27,7 @@ import jakarta.json.JsonObject;
import jakarta.json.JsonValue;
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.spi.JsonbProvider;
+import jakarta.json.stream.JsonGenerator;
import org.apache.johnzon.mapper.Converter;
import org.apache.johnzon.mapper.JohnzonConverter;
@@ -88,8 +89,8 @@ public class JohnzonConverterInJsonbTest {
private static final String TIMESTAMP_JSON_KEY = "timestamp";
@Override
- public void writeJson(TestDTO instance, MappingGenerator
jsonbGenerator) {
- jsonbGenerator.getJsonGenerator().write(TIMESTAMP_JSON_KEY,
instance.instant.atZone(ZoneId.of("UTC")).toString());
+ public void writeJson(TestDTO instance, MappingGenerator
jsonbGenerator, JsonGenerator generator) {
+ generator.write(TIMESTAMP_JSON_KEY,
instance.instant.atZone(ZoneId.of("UTC")).toString());
}
@Override
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 d640c09d..f97802d8 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
@@ -69,7 +69,7 @@ public class SerializerTest {
nameHolder.name.detailName = new DetailName();
nameHolder.name.detailName.name = "Another Test String";
assertEquals(
- "{\"detailName\":{\"name\":\"Another Test
String\",\"detail\":true},\"name\":{\"name\":\"Test String\"}}",
+ "{\"name\":{\"detailName\":{\"name\":\"Another Test
String\",\"detail\":true},\"name\":\"Test String\"}}",
jsonb.toJson(nameHolder));
}
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializersRoundTripTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializersRoundTripTest.java
index 88ef32e9..c6c98395 100644
---
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializersRoundTripTest.java
+++
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializersRoundTripTest.java
@@ -564,7 +564,8 @@ public class SerializersRoundTripTest {
original.color = Color.GREEN;*/
try (final Jsonb jsonb = JsonbBuilder.create()) {
- final Wrapper deserialized =
jsonb.fromJson(jsonb.toJson(original), Wrapper.class);
+ final String json = jsonb.toJson(original);
+ final Wrapper deserialized = jsonb.fromJson(json, Wrapper.class);
assertEquals(original, deserialized);
}
}
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/serializer/SerialiseAsPrimitiveAnnotatedAtClassTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/serializer/SerialiseAsPrimitiveAnnotatedAtClassTest.java
new file mode 100644
index 00000000..19ea2999
--- /dev/null
+++
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/serializer/SerialiseAsPrimitiveAnnotatedAtClassTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.serializer;
+
+import java.lang.reflect.Type;
+
+import org.junit.Test;
+
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+import jakarta.json.bind.annotation.JsonbTypeDeserializer;
+import jakarta.json.bind.annotation.JsonbTypeSerializer;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.bind.serializer.JsonbDeserializer;
+import jakarta.json.bind.serializer.JsonbSerializer;
+import jakarta.json.bind.serializer.SerializationContext;
+import jakarta.json.stream.JsonGenerator;
+import jakarta.json.stream.JsonParser;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * This test checks a JsonbSerialize/JsonbDeserialize roundtrip when using a
primitive as placeholder
+ */
+public class SerialiseAsPrimitiveAnnotatedAtClassTest {
+
+
+ @JsonbTypeSerializer(ConstantJsonbSerialiser.class)
+ @JsonbTypeDeserializer(ConstantJsonbDeserializer.class)
+ public static class TestConstant {
+ public final static TestConstant VAL_1 = new TestConstant("A");
+ public final static TestConstant VAL_2 = new TestConstant("B");
+ public final static TestConstant VAL_3 = new TestConstant("C");
+
+ private final String code;
+
+ public TestConstant(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public static TestConstant getByCode(String code) {
+ switch (code) {
+ case "A": return VAL_1;
+ case "B": return VAL_2;
+ case "C": return VAL_3;
+ default: return null;
+ }
+ }
+ }
+
+ public static class ConstantUsage {
+ private int i;
+
+ private TestConstant testConstant;
+
+ public int getI() {
+ return i;
+ }
+
+ public void setI(int i) {
+ this.i = i;
+ }
+
+ public TestConstant getTestConstant() {
+ return testConstant;
+ }
+
+ public void setTestConstant(TestConstant testEnum) {
+ this.testConstant = testEnum;
+ }
+ }
+
+ public static class ConstantJsonbSerialiser implements
JsonbSerializer<TestConstant> {
+ @Override
+ public void serialize(TestConstant val, JsonGenerator generator,
SerializationContext ctx) {
+ if (val == null) {
+ ctx.serialize(null, generator);
+ } else {
+ ctx.serialize(val.getCode(), generator);
+ }
+ }
+ }
+
+ public static class ConstantJsonbDeserializer implements
JsonbDeserializer<TestConstant> {
+
+ @Override
+ public TestConstant deserialize(JsonParser parser, DeserializationContext
ctx, Type rtType) {
+ if (rtType instanceof TestConstant) {
+ final String key = parser.getString();
+ if (key != null) {
+ return TestConstant.getByCode(key);
+ }
+ }
+
+ return null;
+ }
+}
+
+
+
+ @Test
+ public void testEnumJsonb() {
+ ConstantUsage enumVerwender = new ConstantUsage();
+ enumVerwender.setI(1);
+ enumVerwender.setTestConstant(TestConstant.VAL_2);
+
+ Jsonb jsonb = JsonbBuilder.create();
+ final String json = jsonb.toJson(enumVerwender);
+ assertTrue(json.contains("\"testConstant\":\"B\""));
+ }
+
+}
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 4dce3ddd..e93c42f8 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
@@ -23,6 +23,7 @@ import jakarta.json.stream.JsonGenerator;
import java.math.BigDecimal;
import java.math.BigInteger;
+@Deprecated
public class DynamicMappingGenerator implements MappingGenerator {
private final MappingGenerator delegate;
private final Runnable writeStart;
@@ -40,33 +41,16 @@ public class DynamicMappingGenerator implements
MappingGenerator {
this.writeEnd = writeEnd;
this.keyName = keyName;
}
-
- protected JsonGenerator getRawJsonGenerator() {
- return delegate.getJsonGenerator();
- }
-
- @Override
- public JsonGenerator getJsonGenerator() {
- return generator == null ? generator = new
InObjectOrPrimitiveJsonGenerator(
- getRawJsonGenerator(), writeStart, keyName, writeEnd) :
generator;
- }
+
@Override
public MappingGenerator writeObject(final String key, final Object o,
final JsonGenerator generator) {
- return delegate.writeObject(key, o, ensureGenerator(generator));
+ return delegate.writeObject(key, o, generator);
}
@Override
public MappingGenerator writeObject(final Object o, final JsonGenerator
generator) {
- return delegate.writeObject(o, ensureGenerator(generator));
- }
-
- 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
+ return delegate.writeObject(o, generator);
}
protected void reset() {
@@ -593,24 +577,5 @@ public class DynamicMappingGenerator implements
MappingGenerator {
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/Mapper.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index 34eb512a..267a5327 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
@@ -203,7 +203,7 @@ public class Mapper implements Closeable {
private void writeObject(final Object object, final JsonGenerator
generator, final Collection<String> ignored,
final JsonPointerTracker tracker) {
- final MappingGeneratorImpl mappingGenerator = new
MappingGeneratorImpl(config, generator, mappings);
+ final MappingGeneratorImpl mappingGenerator = new
MappingGeneratorImpl(config, mappings);
mappingGenerator.doWriteObject(object, generator, true, ignored,
tracker);
}
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 23b78dc9..430f03ae 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
@@ -25,6 +25,8 @@ import org.apache.johnzon.mapper.map.LazyConverterMap;
import jakarta.json.Json;
import jakarta.json.JsonValue;
+import jakarta.json.stream.JsonGenerator;
+
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.Collection;
@@ -48,7 +50,7 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig
implements Cloneable {
private static final ObjectConverter.Codec NO_CONVERTER = new
ObjectConverter.Codec() {
@Override
- public void writeJson(Object instance, MappingGenerator
jsonbGenerator) {
+ public void writeJson(Object instance, MappingGenerator
jsonbGenerator, JsonGenerator generator) {
// just a dummy
}
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
index d4ac625f..24a8378d 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
@@ -24,16 +24,11 @@ import jakarta.json.stream.JsonGenerator;
* Handles writing Json for Objects.
* Internally it uses a {@link JsonGenerator} to write JSON
*
- * To write JSON-P structure elements you can use the {@link
#getJsonGenerator()} method.
+ * To write JSON-P structure elements you can use the {@link JsonGenerator}.
*
*/
public interface MappingGenerator {
- /**
- * @return the {@link JsonGenerator} used internally to write the JSON
output.
- */
- JsonGenerator getJsonGenerator();
-
/**
* Write the given Object o into the current JSON layer.
* This will <em>not</em> open a new json layer ('{', '}')
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 4a800612..59016fc4 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
@@ -23,6 +23,7 @@ import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;
import org.apache.johnzon.mapper.internal.JsonPointerTracker;
+import org.apache.johnzon.mapper.jsonp.DeferredStartJsonGenerator;
import org.apache.johnzon.mapper.util.ArrayUtil;
import jakarta.json.JsonValue;
@@ -44,21 +45,14 @@ import java.util.stream.StreamSupport;
public class MappingGeneratorImpl implements MappingGenerator {
private final MapperConfig config;
- private final JsonGenerator generator;
private final Mappings mappings;
private Map<Object, String> jsonPointers;
- MappingGeneratorImpl(MapperConfig config, JsonGenerator jsonGenerator,
final Mappings mappings) {
+ MappingGeneratorImpl(MapperConfig config, final Mappings mappings) {
this.config = config;
- this.generator = jsonGenerator;
this.mappings = mappings;
}
- @Override
- public JsonGenerator getJsonGenerator() {
- return generator;
- }
-
@Override
public MappingGenerator writeObject(final String key, final Object object,
final JsonGenerator generator) {
if (object == null) {
@@ -86,8 +80,9 @@ public class MappingGeneratorImpl implements MappingGenerator
{
} else {
final ObjectConverter.Writer objectConverter =
config.findObjectConverterWriter(objectClass);
if (objectConverter != null) {
- writeWithObjectConverter(new
DynamicMappingGenerator(this,
- generator::writeStartObject,
generator::writeEnd, null), objectConverter, object);
+ DeferredStartJsonGenerator deferredStartJsonGenerator
= new DeferredStartJsonGenerator(generator, key);
+ objectConverter.writeJson(object, this,
deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
} else {
writeValue(objectClass, false, false, false, false,
false, null, key, object,
null, emptyList(), isDedup() ?
JsonPointerTracker.ROOT : null, generator);
@@ -124,7 +119,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
if (writeBody) {
generator.writeStartObject();
}
- writeMapBody((Map<?, ?>) object, null);
+ writeMapBody((Map<?, ?>) object, null, generator);
if (writeBody) {
generator.writeEnd();
}
@@ -145,12 +140,12 @@ public class MappingGeneratorImpl implements
MappingGenerator {
if (objectClass.isArray()) {
final Adapter adapter = config.findAdapter(objectClass);
- writeArray(objectClass, adapter, null, object,
ignoredProperties, jsonPointer);
+ writeArray(objectClass, adapter, null, object,
ignoredProperties, jsonPointer, generator);
return;
}
if (object instanceof Iterable) {
- doWriteIterable((Iterable) object, ignoredProperties,
jsonPointer);
+ doWriteIterable((Iterable) object, ignoredProperties,
jsonPointer, generator);
return;
}
@@ -172,10 +167,11 @@ public class MappingGeneratorImpl implements
MappingGenerator {
ObjectConverter.Writer objectConverter =
config.findObjectConverterWriter(objectClass);
if (writeBody && objectConverter != null) {
if (!writeBody) {
- objectConverter.writeJson(object, this);
+ objectConverter.writeJson(object, this, generator);
} else {
- writeWithObjectConverter(new DynamicMappingGenerator(this,
- generator::writeStartObject, generator::writeEnd,
null), objectConverter, object);
+ DeferredStartJsonGenerator deferredGenerator = new
DeferredStartJsonGenerator(generator, null);
+ objectConverter.writeJson(object, this, deferredGenerator);
+ deferredGenerator.writeEnd();
}
} else {
if (classMapping == null) { // will be created anyway now so
force it and if it has an adapter respect it
@@ -189,7 +185,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
if (writeBody) {
- generator.writeStartObject();
+ generator = new DeferredStartJsonGenerator(generator,
null);
}
final boolean writeEnd = doWriteObjectBody(object,
ignoredProperties, jsonPointer, generator);
@@ -202,8 +198,10 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
}
- private JsonGenerator writeMapBody(final Map<?, ?> object, final Adapter
itemConverter) throws InvocationTargetException, IllegalAccessException {
- for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
+ private JsonGenerator writeMapBody(final Map<?, ?> object, final Adapter
itemConverter,
+ final JsonGenerator generator)
+ throws InvocationTargetException, IllegalAccessException {
+ for (final Map.Entry<?, ?> entry : object.entrySet()) {
final Object value = entry.getValue();
final Object key = entry.getKey();
@@ -363,7 +361,9 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
if (classMapping.writer != null) {
- writeWithObjectConverter(new
DynamicMappingGenerator.SkipEnclosingWriteEnd(this, null, generator),
classMapping.writer, object);
+ DeferredStartJsonGenerator deferredStartJsonGenerator = new
DeferredStartJsonGenerator(generator, null);
+ classMapping.writer.writeJson(object, this,
deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
return false;
}
if (classMapping.adapter != null) {
@@ -429,7 +429,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
if (classMapping.anyGetter != null) {
final Map<String, Object> any =
Map.class.cast(classMapping.anyGetter.reader.read(object));
if (any != null) {
- writeMapBody(any, null);
+ writeMapBody(any, null, generator);
}
}
@@ -452,23 +452,23 @@ public class MappingGeneratorImpl implements
MappingGenerator {
return;
}
if ((!dynamic && array) || (dynamic && type.isArray())) {
- writeArray(type, itemConverter, key, value, ignoredProperties,
jsonPointer);
+ writeArray(type, itemConverter, key, value, ignoredProperties,
jsonPointer, generator);
} else if ((!dynamic && collection) || (dynamic &&
Iterable.class.isAssignableFrom(type))) {
writeIterator(itemConverter, key, objectConverter,
ignoredProperties, jsonPointer, generator,
Iterable.class.cast(value).iterator(), value);
} else if ((!dynamic && map) || (dynamic &&
Map.class.isAssignableFrom(type))) {
- generator.writeStartObject(key);
+ DeferredStartJsonGenerator deferredStartJsonGenerator = new
DeferredStartJsonGenerator(generator, key);
if (objectConverter != null) {
- writeWithObjectConverter(new DynamicMappingGenerator(this,
- () -> this.generator.writeStartObject(key),
this.generator::writeEnd, key), objectConverter, value);
+ objectConverter.writeJson(value, this,
deferredStartJsonGenerator);
} else {
- writeMapBody((Map<?, ?>) value, itemConverter);
+ writeMapBody((Map<?, ?>) value, itemConverter,
deferredStartJsonGenerator);
}
- generator.writeEnd();
+ deferredStartJsonGenerator.writeEnd();
} else if ((!dynamic && primitive) || (dynamic &&
Mappings.isPrimitive(type))) {
if (objectConverter != null) {
- writeWithObjectConverter(new DynamicMappingGenerator(this,
- () -> this.generator.writeStartObject(key),
this.generator::writeEnd, key), objectConverter, value);
+ DeferredStartJsonGenerator deferredStartJsonGenerator = new
DeferredStartJsonGenerator(generator, key);
+ objectConverter.writeJson(value, this,
deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
} else {
writePrimitives(key, type, value, generator);
}
@@ -478,8 +478,9 @@ public class MappingGeneratorImpl implements
MappingGenerator {
} else if (Iterator.class.isAssignableFrom(type)) {
if (objectConverter != null) {
generator.writeStartObject(key);
+ //X TODO 2 writeStartObject? sounds fishy...
writeWithObjectConverter(new DynamicMappingGenerator(this,
- () -> this.generator.writeStartObject(key),
this.generator::writeEnd, key), objectConverter, value);
+ () -> generator.writeStartObject(key),
generator::writeEnd, key), objectConverter, value, generator);
generator.writeEnd();
} else {
writeIterator(itemConverter, key, objectConverter,
ignoredProperties, jsonPointer, generator,
@@ -487,8 +488,9 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
} else {
if (objectConverter != null) {
- writeWithObjectConverter(new DynamicMappingGenerator(this,
- () -> this.generator.writeStartObject(key),
this.generator::writeEnd, key), objectConverter, value);
+ DeferredStartJsonGenerator deferredStartJsonGenerator = new
DeferredStartJsonGenerator(generator, key);
+ objectConverter.writeJson(value, this,
deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
return;
}
@@ -507,26 +509,27 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
if (objectConverterToUse != null) {
- writeWithObjectConverter(new DynamicMappingGenerator(this,
- () -> this.generator.writeStartObject(key),
this.generator::writeEnd, key), objectConverterToUse, value);
+ DeferredStartJsonGenerator deferredStartJsonGenerator =
new DeferredStartJsonGenerator(generator, key);
+ objectConverterToUse.writeJson(value, this,
deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
return;
}
}
if (writePrimitives(key, type, value, generator)) {
return;
}
- generator.writeStartObject(key);
- if (doWriteObjectBody(value, ignoredProperties, jsonPointer,
generator)) {
- generator.writeEnd();
+ DeferredStartJsonGenerator deferredStartGenerator = new
DeferredStartJsonGenerator(generator, key);
+ if (doWriteObjectBody(value, ignoredProperties, jsonPointer,
deferredStartGenerator)) {
+ deferredStartGenerator.writeEnd();
}
}
}
- private void writeWithObjectConverter(final DynamicMappingGenerator
generator,
+ @Deprecated
+ private void writeWithObjectConverter(final DynamicMappingGenerator
dynamicMappingGenerator,
final ObjectConverter.Writer
objectConverter,
- final Object value) {
- final DynamicMappingGenerator dynamicMappingGenerator = generator;
- objectConverter.writeJson(value, dynamicMappingGenerator);
+ final Object value, JsonGenerator
generator) {
+ objectConverter.writeJson(value, dynamicMappingGenerator, generator);
dynamicMappingGenerator.flushIfNeeded();
}
@@ -542,8 +545,9 @@ public class MappingGeneratorImpl implements
MappingGenerator {
List.class.cast(originalValue) :
StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator,
Spliterator.IMMUTABLE), false)
.collect(toList());
- objectConverter.writeJson(list, new DynamicMappingGenerator(
- this, generator::writeStartArray, generator::writeEnd,
key));
+ DeferredStartJsonGenerator deferredStartJsonGenerator = new
DeferredStartJsonGenerator(generator, key, true);
+ objectConverter.writeJson(list, this, deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
return;
}
@@ -562,11 +566,12 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
if (objectConverterToUse != null) {
- writeWithObjectConverter(new DynamicMappingGenerator(this,
- generator::writeStartObject, generator::writeEnd,
null), objectConverterToUse, o);
+ DeferredStartJsonGenerator deferredStartJsonGenerator =
new DeferredStartJsonGenerator(generator, null);
+ objectConverterToUse.writeJson(o, this,
deferredStartJsonGenerator);
+ deferredStartJsonGenerator.writeEnd();
} else {
writeItem(itemConverter != null ? itemConverter.from(o) :
o, ignoredProperties,
- isDedup() ? new JsonPointerTracker(jsonPointer, i)
: null);
+ isDedup() ? new JsonPointerTracker(jsonPointer, i)
: null, generator);
}
}
i++;
@@ -576,9 +581,12 @@ public class MappingGeneratorImpl implements
MappingGenerator {
/**
* Write a JSON Array with a given Array Value, like byte[], int[],
Person[] etc.
- * @param key either the attribute key or {@code null} if the array should
be rendered without key
+ *
+ * @param key either the attribute key or {@code null} if the array
should be rendered without key
+ * @param generator
*/
- private void writeArray(Class<?> type, Adapter itemConverter, String key,
Object arrayValue, Collection<String> ignoredProperties, JsonPointerTracker
jsonPointer) {
+ private void writeArray(Class<?> type, Adapter itemConverter, String key,
Object arrayValue, Collection<String> ignoredProperties, JsonPointerTracker
jsonPointer,
+ final JsonGenerator generator) {
final int length = ArrayUtil.getArrayLength(arrayValue);
if (length == 0 && config.isSkipEmptyArray()) {
return;
@@ -671,7 +679,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
for (int i = 0; i < length; i++) {
final Object o = oArrayValue[i];
writeItem(itemConverter != null ? itemConverter.from(o) : o,
ignoredProperties,
- isDedup() ? new JsonPointerTracker(jsonPointer, i) :
null);
+ isDedup() ? new JsonPointerTracker(jsonPointer, i) :
null, generator);
}
} else {
// must be object arrays
@@ -686,7 +694,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
generator.write((JsonValue) o);
} else {
writeItem(itemConverter != null ? itemConverter.from(o) :
o, ignoredProperties,
- isDedup() ? new JsonPointerTracker(jsonPointer, i)
: null);
+ isDedup() ? new JsonPointerTracker(jsonPointer, i)
: null, generator);
}
}
}
@@ -694,16 +702,17 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
- private void writeItem(final Object o, final Collection<String>
ignoredProperties, JsonPointerTracker jsonPointer) {
+ private void writeItem(final Object o, final Collection<String>
ignoredProperties, JsonPointerTracker jsonPointer,
+ final JsonGenerator generator) {
if (o == null) {
generator.writeNull();
} else if (!writePrimitives(o, generator)) {
if (Collection.class.isInstance(o)) {
- doWriteIterable(Collection.class.cast(o), ignoredProperties,
jsonPointer);
+ doWriteIterable(Collection.class.cast(o), ignoredProperties,
jsonPointer, generator);
} else if (o.getClass().isArray()) {
final int length = ArrayUtil.getArrayLength(o);
if (length > 0 || !config.isSkipEmptyArray()) {
- writeArray(o.getClass(), null, null, o, ignoredProperties,
jsonPointer);
+ writeArray(o.getClass(), null, null, o, ignoredProperties,
jsonPointer, generator);
}
} else {
String valJsonPointer = jsonPointers == null ? null :
jsonPointers.get(o);
@@ -717,7 +726,8 @@ public class MappingGeneratorImpl implements
MappingGenerator {
}
}
- private <T> void doWriteIterable(final Iterable<T> object, final
Collection<String> ignoredProperties, JsonPointerTracker jsonPointer) {
+ private <T> void doWriteIterable(final Iterable<T> object, final
Collection<String> ignoredProperties, JsonPointerTracker jsonPointer,
+ final JsonGenerator generator) {
if (object == null) {
generator.writeStartArray().writeEnd();
} else {
@@ -730,7 +740,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
if (t == null) {
generator.writeNull();
} else {
- writeItem(t, ignoredProperties, isDedup() ? new
JsonPointerTracker(jsonPointer, i) : null);
+ writeItem(t, ignoredProperties, isDedup() ? new
JsonPointerTracker(jsonPointer, i) : null, generator);
}
}
i++;
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
index 57098715..ceee7a6a 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
@@ -19,6 +19,7 @@
package org.apache.johnzon.mapper;
import jakarta.json.JsonValue;
+import jakarta.json.stream.JsonGenerator;
import java.lang.reflect.Type;
@@ -36,7 +37,7 @@ public final class ObjectConverter {
}
public interface Writer<T> extends MapperConverter {
- void writeJson(T instance, MappingGenerator jsonbGenerator);
+ void writeJson(T instance, MappingGenerator jsonbGenerator,
JsonGenerator generator);
// returns true if it is for containers - if any - and not each
container item (ex: list)
default boolean isGlobal() {
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/jsonp/DeferredStartJsonGenerator.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/jsonp/DeferredStartJsonGenerator.java
new file mode 100644
index 00000000..b6909274
--- /dev/null
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/jsonp/DeferredStartJsonGenerator.java
@@ -0,0 +1,354 @@
+/*
+ * 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.jsonp;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import jakarta.json.JsonValue;
+import jakarta.json.stream.JsonGenerator;
+
+
+/**
+ * This JsonGenerator will not automatically write a startObject '{'
character, but only if needed.
+ *
+ * The {@link #writeEnd()} method will only write a closing '}' if a start has
been written before.
+ *
+ * This class must only be used in cases where you would call {@code
jsonGenerator.startObject(key)} !
+ */
+public class DeferredStartJsonGenerator implements JsonGenerator {
+
+ private final JsonGenerator delegate;
+ private final String key;
+ private final boolean array;
+
+ private boolean started = false;
+ private boolean empty = true;
+
+ // this is needed to make sure we don't close more layers than we did open.
+ private int depth = 0;
+
+ /**
+ * Deferred start for Objects
+ *
+ * @see #DeferredStartJsonGenerator(JsonGenerator, String, boolean)
+ */
+ public DeferredStartJsonGenerator(JsonGenerator delegate, String key) {
+ this(delegate, key, false);
+ }
+
+ /**
+ * JsonGenerator which only writes a start character if an embedded json
structure is later written.
+ *
+ * @param delegate JsonGenerator which really writes
+ * @param key for the startObject, or {@code null} if no key should be used
+ * @param array if {@code true} we will use a start with a '[', otherwise
with an object start '{'
+ */
+ public DeferredStartJsonGenerator(JsonGenerator delegate, String key,
boolean array) {
+ this.delegate = delegate;
+ this.key = key;
+ this.array = array;
+ }
+
+ private void ensureStart() {
+ if (!started) {
+ if (array) {
+ if (key != null) {
+ delegate.writeStartArray(key);
+ } else {
+ delegate.writeStartArray();
+ }
+ } else {
+ if (key != null) {
+ delegate.writeStartObject(key);
+ } else {
+ delegate.writeStartObject();
+ }
+ }
+ started = true;
+ depth++;
+ }
+ }
+
+ @Override
+ public void close() {
+ writeEnd();
+ delegate.close();
+ }
+
+ @Override
+ public void flush() {
+ delegate.flush();
+ }
+
+ @Override
+ public JsonGenerator write(String name, BigDecimal value) {
+ ensureStart();
+ empty = false;
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, BigInteger value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, boolean value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, double value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, int value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, JsonValue value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, long value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String name, String value) {
+ ensureStart();
+ delegate.write(name, value);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(BigDecimal value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(BigInteger value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(boolean value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(double value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(int value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(JsonValue value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(long value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator write(String value) {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.write(key, value);
+ } else {
+ delegate.write(value);
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeEnd() {
+ if (empty) {
+ if (key != null) {
+ delegate.writeStartObject(key);
+ } else {
+ delegate.writeStartObject();
+ }
+ started = true;
+ depth++;
+ }
+ if (started && depth > 0) {
+ delegate.writeEnd();
+ depth--;
+ }
+
+
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeKey(String name) {
+ delegate.writeKey(name);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeNull() {
+ if (!started && key != null) {
+ // means we write a value instead of an object
+ delegate.writeNull(key);
+ } else {
+ delegate.writeNull();
+ }
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeNull(String name) {
+ ensureStart();
+ delegate.writeNull(name);
+ empty = false;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartArray() {
+ // safeguard if Converters, Serializers ets do a manual startArray()
+ if (key != null && !started) {
+ delegate.writeStartArray(key);
+ } else {
+ delegate.writeStartArray();
+ }
+ started = true;
+ empty = false;
+ depth++;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartArray(String name) {
+ ensureStart();
+ delegate.writeStartArray(name);
+ started = true;
+ empty = false;
+ depth++;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartObject() {
+ // safeguard if Converters, Serializers ets do a manual startObject()
+ if (key != null && !started) {
+ delegate.writeStartObject(key);
+ } else {
+ delegate.writeStartObject();
+ }
+
+ started = true;
+ empty = false;
+ depth++;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator writeStartObject(String name) {
+ ensureStart();
+ started = true;
+ delegate.writeStartObject(name);
+ empty = false;
+ depth++;
+ return this;
+ }
+}
diff --git
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
index c9429536..5f42d8e2 100644
---
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
+++
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
@@ -27,6 +27,7 @@ import org.junit.Assert;
import org.junit.Test;
import jakarta.json.JsonValue;
+import jakarta.json.stream.JsonGenerator;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
@@ -189,7 +190,7 @@ public class MapperConfigTest {
private static class TheConverter<T> implements ObjectConverter.Codec<T>{
@Override
- public void writeJson(T instance, MappingGenerator jsonbGenerator) {
+ public void writeJson(T instance, MappingGenerator jsonbGenerator,
JsonGenerator generator) {
// dummy
}
@@ -202,7 +203,7 @@ public class MapperConfigTest {
private static abstract class TheAbstractConverter<T extends TheInterface>
implements ObjectConverter.Codec<T> {
@Override
- public void writeJson(T instance, MappingGenerator jsonbGenerator) {
+ public void writeJson(T instance, MappingGenerator jsonbGenerator,
JsonGenerator generator) {
// dummy
}
diff --git
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
index 82ae4614..cca78423 100644
---
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
+++
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
@@ -24,6 +24,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import jakarta.json.JsonValue;
+import jakarta.json.stream.JsonGenerator;
import java.beans.ConstructorProperties;
import java.lang.reflect.Type;
@@ -388,11 +389,11 @@ public class ObjectConverterWithAnnotationTest {
@Override
- public void writeJson(Bike instance, MappingGenerator jsonbGenerator) {
- jsonbGenerator.getJsonGenerator().write(MANUFACTURER_ID,
MANUFACTURERS.indexOf(instance.getManufacturer()));
+ public void writeJson(Bike instance, MappingGenerator jsonbGenerator,
JsonGenerator generator) {
+ generator.write(MANUFACTURER_ID,
MANUFACTURERS.indexOf(instance.getManufacturer()));
// i know you should never use this in production but its good for
our sample ;)
- jsonbGenerator.getJsonGenerator().write(TYPE_INDEX,
instance.getType().ordinal());
+ generator.write(TYPE_INDEX, instance.getType().ordinal());
}
@Override
diff --git
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
index 36c76161..38300297 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
@@ -25,6 +25,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import jakarta.json.JsonValue;
+import jakarta.json.stream.JsonGenerator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -200,9 +201,9 @@ public class ObjectTypeTest {
public static class TestWithTypeConverter implements
ObjectConverter.Codec<Dog> {
@Override
- public void writeJson(Dog instance, MappingGenerator mappingGenerator)
{
- mappingGenerator.getJsonGenerator().write("//javaType",
instance.getClass().getName());
- mappingGenerator.writeObject(instance,
mappingGenerator.getJsonGenerator());
+ public void writeJson(Dog instance, MappingGenerator mappingGenerator,
JsonGenerator generator) {
+ generator.write("//javaType", instance.getClass().getName());
+ mappingGenerator.writeObject(instance, generator);
}
@Override
@@ -420,8 +421,8 @@ public class ObjectTypeTest {
}
@Override
- public void writeJson(Poodle instance, MappingGenerator
jsonbGenerator) {
- jsonbGenerator.getJsonGenerator().write("poodleName",
instance.getName());
+ public void writeJson(Poodle instance, MappingGenerator
jsonbGenerator, JsonGenerator generator) {
+ generator.write("poodleName", instance.getName());
}
@Override