Repository: johnzon Updated Branches: refs/heads/master 08905f99e -> 52f0aab8e
JOHNZON-77/JOHNZON-142 implemented ObjectConverter support for constructors Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/52f0aab8 Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/52f0aab8 Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/52f0aab8 Branch: refs/heads/master Commit: 52f0aab8ed32151b34528e1e48304682a4449f34 Parents: 08905f9 Author: Reinhard Sandtner <[email protected]> Authored: Tue Oct 31 22:08:53 2017 +0100 Committer: Reinhard Sandtner <[email protected]> Committed: Tue Oct 31 22:09:41 2017 +0100 ---------------------------------------------------------------------- .../apache/johnzon/jsonb/JsonbAccessMode.java | 66 +++++++++++++++----- .../johnzon/mapper/MappingParserImpl.java | 2 +- .../johnzon/mapper/access/AccessMode.java | 1 + .../johnzon/mapper/access/BaseAccessMode.java | 10 ++- .../johnzon/mapper/access/FieldAccessMode.java | 9 +-- .../ObjectConverterWithAnnotationTest.java | 33 ++++++++++ 6 files changed, 98 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/52f0aab8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java ---------------------------------------------------------------------- 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 3b020d2..5852177 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 @@ -30,6 +30,7 @@ import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext; import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory; import org.apache.johnzon.mapper.Adapter; import org.apache.johnzon.mapper.JohnzonAny; +import org.apache.johnzon.mapper.JohnzonConverter; import org.apache.johnzon.mapper.ObjectConverter; import org.apache.johnzon.mapper.TypeAwareAdapter; import org.apache.johnzon.mapper.access.AccessMode; @@ -166,11 +167,14 @@ public class JsonbAccessMode implements AccessMode, Closeable { final String[] params; final Adapter<?, ?>[] converters; final Adapter<?, ?>[] itemConverters; + final ObjectConverter.Codec<?>[] objectConverters; if (finalConstructor != null || finalFactory != null) { types = finalConstructor != null ? finalConstructor.getGenericParameterTypes() : finalFactory.getGenericParameterTypes(); params = new String[types.length]; converters = new Adapter<?, ?>[types.length]; itemConverters = new Adapter<?, ?>[types.length]; + objectConverters = new ObjectConverter.Codec<?>[types.length]; + int i = 0; for (final Parameter parameter : (finalConstructor == null ? finalFactory : finalConstructor).getParameters()) { final JsonbProperty property = getAnnotation(parameter, JsonbProperty.class); @@ -179,20 +183,25 @@ public class JsonbAccessMode implements AccessMode, Closeable { final JsonbTypeAdapter adapter = getAnnotation(parameter, JsonbTypeAdapter.class); final JsonbDateFormat dateFormat = getAnnotation(parameter, JsonbDateFormat.class); final JsonbNumberFormat numberFormat = getAnnotation(parameter, JsonbNumberFormat.class); - if (adapter == null && dateFormat == null && numberFormat == null) { + final JohnzonConverter johnzonConverter = getAnnotation(parameter, JohnzonConverter.class); + if (adapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null) { converters[i] = defaultConverters.get(parameter.getType()); itemConverters[i] = null; } else { - validateAnnotations(parameter, adapter, dateFormat, numberFormat); + validateAnnotations(parameter, adapter, dateFormat, numberFormat, johnzonConverter); try { - final Adapter converter = toConverter(parameter.getType(), adapter, dateFormat, numberFormat); - if (matches(parameter.getParameterizedType(), converter)) { - converters[i] = converter; - itemConverters[i] = null; - } else { - converters[i] = null; - itemConverters[i] = converter; + if (adapter != null) { + final Adapter converter = toConverter(parameter.getType(), adapter, dateFormat, numberFormat); + if (matches(parameter.getParameterizedType(), converter)) { + converters[i] = converter; + itemConverters[i] = null; + } else { + converters[i] = null; + itemConverters[i] = converter; + } + } else if (johnzonConverter != null) { + objectConverters[i] = (ObjectConverter.Codec<?>) johnzonConverter.value().newInstance(); } } catch (final InstantiationException | IllegalAccessException e) { throw new IllegalArgumentException(e); @@ -206,6 +215,7 @@ public class JsonbAccessMode implements AccessMode, Closeable { params = null; converters = null; itemConverters = null; + objectConverters = null; } return constructor == null && factory == null ? delegate.findFactory(clazz) : ( @@ -241,6 +251,11 @@ public class JsonbAccessMode implements AccessMode, Closeable { public Adapter<?, ?>[] getParameterItemConverter() { return itemConverters; } + + @Override + public ObjectConverter.Codec<?>[] getObjectConverter() { + return objectConverters; + } } : new Factory() { @Override @@ -277,17 +292,24 @@ public class JsonbAccessMode implements AccessMode, Closeable { public Adapter<?, ?>[] getParameterItemConverter() { return itemConverters; } + + @Override + public ObjectConverter.Codec<?>[] getObjectConverter() { + return objectConverters; + } }); } private void validateAnnotations(final Object parameter, final JsonbTypeAdapter adapter, final JsonbDateFormat dateFormat, - final JsonbNumberFormat numberFormat) { + final JsonbNumberFormat numberFormat, + final JohnzonConverter johnzonConverter) { int notNull = adapter != null ? 1 : 0; notNull += dateFormat != null ? 1 : 0; notNull += numberFormat != null ? 1 : 0; + notNull += johnzonConverter != null ? 1 : 0; if (notNull > 1) { - throw new IllegalArgumentException("Conflicting @JsonbXXX on " + parameter); + throw new IllegalArgumentException("Conflicting @JsonbXXX/@JohnzonConverter on " + parameter); } } @@ -685,7 +707,8 @@ public class JsonbAccessMode implements AccessMode, Closeable { final JsonbTypeAdapter adapter = annotationHolder.getAnnotation(JsonbTypeAdapter.class); final JsonbDateFormat dateFormat = annotationHolder.getAnnotation(JsonbDateFormat.class); final JsonbNumberFormat numberFormat = annotationHolder.getAnnotation(JsonbNumberFormat.class); - validateAnnotations(annotationHolder, adapter, dateFormat, numberFormat); + final JohnzonConverter johnzonConverter = annotationHolder.getAnnotation(JohnzonConverter.class); + validateAnnotations(annotationHolder, adapter, dateFormat, numberFormat, johnzonConverter); try { converter = adapter == null && dateFormat == null && numberFormat == null ? @@ -705,8 +728,12 @@ public class JsonbAccessMode implements AccessMode, Closeable { toRelease.add(instance); reader = (jsonObject, targetType, parser) -> instance.getValue().deserialize(parserFactory.get().createParser(jsonObject), new JohnzonDeserializationContext(parser), targetType); - } else { - reader = null; + } else if (johnzonConverter != null) { + try { + reader = (ObjectConverter.Reader) johnzonConverter.value().newInstance(); + } catch (final InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException(e); + } } } } @@ -720,7 +747,8 @@ public class JsonbAccessMode implements AccessMode, Closeable { final JsonbTypeAdapter adapter = initialReader.getAnnotation(JsonbTypeAdapter.class); final JsonbDateFormat dateFormat = initialReader.getAnnotation(JsonbDateFormat.class); final JsonbNumberFormat numberFormat = initialReader.getAnnotation(JsonbNumberFormat.class); - validateAnnotations(initialReader, adapter, dateFormat, numberFormat); + final JohnzonConverter johnzonConverter = initialReader.getAnnotation(JohnzonConverter.class); + validateAnnotations(initialReader, adapter, dateFormat, numberFormat, johnzonConverter); try { converter = adapter == null && dateFormat == null && numberFormat == null ? @@ -740,8 +768,12 @@ public class JsonbAccessMode implements AccessMode, Closeable { toRelease.add(instance); writer = (instance1, jsonbGenerator) -> instance.getValue().serialize(instance1, jsonbGenerator.getJsonGenerator(), new JohnzonSerializationContext(jsonbGenerator)); - } else { - writer = null; + } else if (johnzonConverter != null) { + try { + writer = (ObjectConverter.Writer) johnzonConverter.value().newInstance(); + } catch (final InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException(e); + } } } } http://git-wip-us.apache.org/repos/asf/johnzon/blob/52f0aab8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java index 383b10c..41731d4 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java @@ -666,7 +666,7 @@ public class MappingParserImpl implements MappingParser { mapping.factory.getParameterConverter()[i], mapping.factory.getParameterItemConverter()[i], mapping.factory.getParameterTypes()[i], - null, + mapping.factory.getObjectConverter()[i], config.isDeduplicateObjects() ? new JsonPointerTracker(jsonPointer, paramName) : null); //X TODO ObjectConverter in @JOhnzonConverter with Constructors! } http://git-wip-us.apache.org/repos/asf/johnzon/blob/52f0aab8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java index 8575aa3..4d590bf 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java @@ -52,6 +52,7 @@ public interface AccessMode { String[] getParameterNames(); Adapter<?, ?>[] getParameterConverter(); Adapter<?, ?>[] getParameterItemConverter(); + ObjectConverter.Codec<?>[] getObjectConverter(); } Factory findFactory(Class<?> clazz); http://git-wip-us.apache.org/repos/asf/johnzon/blob/52f0aab8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java index e1bba2e..36200ad 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java @@ -134,6 +134,7 @@ public abstract class BaseAccessMode implements AccessMode { final String[] constructorParameters; final Adapter<?, ?>[] constructorParameterConverters; final Adapter<?, ?>[] constructorItemParameterConverters; + final ObjectConverter.Codec<?>[] objectConverters; if (constructorHasArguments) { factoryParameterTypes = constructor.getGenericParameterTypes(); @@ -143,6 +144,7 @@ public abstract class BaseAccessMode implements AccessMode { constructorParameterConverters = new Adapter<?, ?>[constructor.getGenericParameterTypes().length]; constructorItemParameterConverters = new Adapter<?, ?>[constructorParameterConverters.length]; + objectConverters = new ObjectConverter.Codec[constructorParameterConverters.length]; for (int i = 0; i < constructorParameters.length; i++) { for (final Annotation a : constructor.getParameterAnnotations()[i]) { if (a.annotationType() == JohnzonConverter.class) { @@ -158,7 +160,7 @@ public abstract class BaseAccessMode implements AccessMode { constructorItemParameterConverters[i] = converter; } } else { - throw new UnsupportedOperationException("TODO implement"); + objectConverters[i] = (ObjectConverter.Codec<?>) mapperConverter; } } catch (final Exception e) { throw new IllegalArgumentException(e); @@ -171,6 +173,7 @@ public abstract class BaseAccessMode implements AccessMode { constructorParameters = null; constructorParameterConverters = null; constructorItemParameterConverters = null; + objectConverters = null; } final Constructor<?> cons = constructor; @@ -213,6 +216,11 @@ public abstract class BaseAccessMode implements AccessMode { public Adapter<?, ?>[] getParameterItemConverter() { return constructorItemParameterConverters; } + + @Override + public ObjectConverter.Codec<?>[] getObjectConverter() { + return objectConverters; + } }; } http://git-wip-us.apache.org/repos/asf/johnzon/blob/52f0aab8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java index cff4358..f2cec48 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java @@ -39,7 +39,7 @@ public class FieldAccessMode extends BaseAccessMode { @Override public Map<String, Reader> doFindReaders(final Class<?> clazz) { final Map<String, Reader> readers = new HashMap<String, Reader>(); - for (final Map.Entry<String, Field> f : fields(clazz).entrySet()) { + for (final Map.Entry<String, Field> f : fields(clazz, true).entrySet()) { final String key = f.getKey(); if (isIgnored(key) || Meta.getAnnotation(f.getValue(), JohnzonAny.class) != null) { continue; @@ -54,7 +54,7 @@ public class FieldAccessMode extends BaseAccessMode { @Override public Map<String, Writer> doFindWriters(final Class<?> clazz) { final Map<String, Writer> writers = new HashMap<String, Writer>(); - for (final Map.Entry<String, Field> f : fields(clazz).entrySet()) { + for (final Map.Entry<String, Field> f : fields(clazz, false).entrySet()) { final String key = f.getKey(); if (isIgnored(key)) { continue; @@ -75,7 +75,7 @@ public class FieldAccessMode extends BaseAccessMode { return key.contains("$"); } - protected Map<String, Field> fields(final Class<?> clazz) { + protected Map<String, Field> fields(final Class<?> clazz, boolean includeFinalFields) { final Map<String, Field> fields = new HashMap<String, Field>(); Class<?> current = clazz; while (current != null && current != Object.class) { @@ -84,7 +84,8 @@ public class FieldAccessMode extends BaseAccessMode { final int modifiers = f.getModifiers(); if (fields.containsKey(name) || Modifier.isStatic(modifiers) - || Modifier.isTransient(modifiers)) { + || Modifier.isTransient(modifiers) + || (!includeFinalFields && Modifier.isFinal(modifiers))) { continue; } fields.put(name, f); http://git-wip-us.apache.org/repos/asf/johnzon/blob/52f0aab8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java ---------------------------------------------------------------------- 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 510672d..c465f8b 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 javax.json.JsonObject; +import java.beans.ConstructorProperties; import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; @@ -159,6 +160,38 @@ public class ObjectConverterWithAnnotationTest { Assert.assertEquals(expected, tourDeFlanderen); } + @Test + public void testDeserializeObjectWithAnnotatedConsturctorParameter() { + + String json = "{" + + "\"bike\": {" + + "\"" + MANUFACTURER_ID + "\":1," + + "\"" + TYPE_INDEX + "\":0" + + "}" + + "}"; + + Mapper mapper = new MapperBuilder().setAccessModeName(accessMode) + .setReadAttributeBeforeWrite(true) + .build(); + + BikeWrapper bikeWrapper = mapper.readObject(json, BikeWrapper.class); + Assert.assertNotNull(bikeWrapper); + Assert.assertEquals(bikeWrapper.getBike(), new Bike("Canyon", BikeType.ROAD)); + } + + public static class BikeWrapper { + private final Bike bike; + + @ConstructorProperties(value = "bike") + BikeWrapper(@JohnzonConverter(value = BikeConverter.class) Bike bike) { + this.bike = bike; + } + + Bike getBike() { + return bike; + } + } + public static class CycleRace { private boolean monument;
