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> {

Reply via email to