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 <[email protected]>
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> {