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 a4e9a87 JOHNZON-303 a class with some generic should be able to map a container (list/map) using this generic a4e9a87 is described below commit a4e9a87ab2bb38aabb53b97447e9b1079c13454d Author: Romain Manni-Bucau <rmannibu...@apache.org> AuthorDate: Tue Mar 10 13:22:43 2020 +0100 JOHNZON-303 a class with some generic should be able to map a container (list/map) using this generic --- .../java/org/apache/johnzon/mapper/Mappings.java | 4 +- .../apache/johnzon/mapper/reflection/Generics.java | 22 +++++++---- .../org/apache/johnzon/mapper/GenericsTest.java | 43 +++++++++++++++++----- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java index 0f623a1..6991c9d 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java @@ -327,7 +327,7 @@ public class Mappings { } final CollectionMapping mapping = new CollectionMapping(isPrimitive(fieldArgTypes[0]), collectionType, - Generics.resolve(fieldArgTypes[0], root)); + Generics.resolve(fieldArgTypes[0], root, emptyMap())); collections.putIfAbsent(aType, mapping); return mapping; } @@ -529,7 +529,7 @@ public class Mappings { final Setter setter = new Setter( value, isPrimitive(param), (returnType != null && returnType.isArray()) || GenericArrayType.class.isInstance(value.getType()), - resolve(param, rootClass), + resolve(param, rootClass, resolvedTypes), findConverter(copyDate, value), value.findObjectConverterReader(), writeIgnore != null ? writeIgnore.minVersion() : -1); setters.put(key, setter); diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Generics.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Generics.java index f79e82e..1b7969f 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Generics.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Generics.java @@ -61,12 +61,13 @@ public final class Generics { // - wildcard support? // - cycle handling (Foo<Foo>) // - .... - public static Type resolve(final Type value, final Type rootClass) { + public static Type resolve(final Type value, final Type rootClass, + final Map<Type, Type> resolved) { if (TypeVariable.class.isInstance(value)) { - return resolveTypeVariable(value, rootClass); + return resolveTypeVariable(value, rootClass, resolved); } if (ParameterizedType.class.isInstance(value)) { - return resolveParameterizedType(value, rootClass); + return resolveParameterizedType(value, rootClass, resolved); } if (WildcardType.class.isInstance(value)) { return resolveWildcardType(value); @@ -83,12 +84,13 @@ public final class Generics { return value; } - private static Type resolveParameterizedType(final Type value, final Type rootClass) { + private static Type resolveParameterizedType(final Type value, final Type rootClass, + final Map<Type, Type> resolved) { Collection<Type> args = null; final ParameterizedType parameterizedType = ParameterizedType.class.cast(value); int index = 0; for (final Type arg : parameterizedType.getActualTypeArguments()) { - final Type type = resolve(arg, rootClass); + final Type type = resolve(arg, rootClass, resolved); if (type != arg) { if (args == null) { args = new ArrayList<>(); @@ -109,7 +111,13 @@ public final class Generics { } // for now the level is hardcoded to 2 with generic > concrete - private static Type resolveTypeVariable(final Type value, final Type rootClass) { + private static Type resolveTypeVariable(final Type value, final Type rootClass, + final Map<Type, Type> resolved) { + final Type alreadyResolved = resolved.get(value); + if (alreadyResolved != null) { + return alreadyResolved; + } + final TypeVariable<?> tv = TypeVariable.class.cast(value); Type parent = rootClass; while (Class.class.isInstance(parent)) { @@ -124,7 +132,7 @@ public final class Generics { if (argIndex >= 0) { final Type type = parentPt.getActualTypeArguments()[argIndex]; if (TypeVariable.class.isInstance(type)) { - return resolveTypeVariable(type, rootClass); + return resolveTypeVariable(type, rootClass, resolved); } return type; } diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GenericsTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GenericsTest.java index eaf831a..8594559 100644 --- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GenericsTest.java +++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/GenericsTest.java @@ -30,6 +30,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Queue; +import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType; import org.junit.Test; import org.superbiz.Model; @@ -94,16 +95,38 @@ public class GenericsTest { public void typeVariableMultiLevel() { final String input = "{\"aalist\":[{\"detail\":\"something2\",\"name\":\"Na2\"}]," + "\"childA\":{\"detail\":\"something\",\"name\":\"Na\"},\"childB\":{}}"; - final Mapper mapper = new MapperBuilder().setAttributeOrder(String::compareTo).build(); - final Model model = mapper.readObject(input, Model.class); - assertNotNull(model.getChildA()); - assertNotNull(model.getChildB()); - assertNotNull(model.getAalist()); - assertEquals("something", model.getChildA().detail); - assertEquals("Na", model.getChildA().name); - assertEquals(1, model.getAalist().size()); - assertEquals("something2", model.getAalist().iterator().next().detail); - assertEquals(input, mapper.writeObjectAsString(model)); + try (final Mapper mapper = new MapperBuilder().setAttributeOrder(String::compareTo).build()) { + final Model model = mapper.readObject(input, Model.class); + assertNotNull(model.getChildA()); + assertNotNull(model.getChildB()); + assertNotNull(model.getAalist()); + assertEquals("something", model.getChildA().detail); + assertEquals("Na", model.getChildA().name); + assertEquals(1, model.getAalist().size()); + assertEquals("something2", model.getAalist().iterator().next().detail); + assertEquals(input, mapper.writeObjectAsString(model)); + } + } + + @Test + public void genericClasses() { + final String input = "{\"aalist\":[{\"name\":\"Na2\"}]}"; + try (final Mapper mapper = new MapperBuilder().setAttributeOrder(String::compareTo).build()) { + final GenericModel<SimpleModel> model = mapper.readObject( + input, new JohnzonParameterizedType(GenericModel.class, SimpleModel.class)); + assertNotNull(model.aalist); + assertEquals(1, model.aalist.size()); + assertEquals("Na2", model.aalist.get(0).name); + assertEquals(input, mapper.writeObjectAsString(model)); + } + } + + public static class SimpleModel { + public String name; + } + + public static class GenericModel<T> { + public List<T> aalist; } public interface Holder<T> {