You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2015/08/31 15:30:22 UTC
incubator-johnzon git commit: JOHNZON-56 basic one level support of
generics
Repository: incubator-johnzon
Updated Branches:
refs/heads/master a78c0cc5d -> 8841d7550
JOHNZON-56 basic one level support of generics
Project: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/commit/8841d755
Tree: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/tree/8841d755
Diff: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/diff/8841d755
Branch: refs/heads/master
Commit: 8841d755094293f658a5764149e9a2010e30da12
Parents: a78c0cc
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Mon Aug 31 15:29:45 2015 +0200
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Mon Aug 31 15:29:45 2015 +0200
----------------------------------------------------------------------
.../johnzon/mapper/access/BaseAccessMode.java | 49 ++++++++++++++
.../johnzon/mapper/access/FieldAccessMode.java | 26 ++++---
.../johnzon/mapper/access/MethodAccessMode.java | 38 +++++------
.../johnzon/mapper/MapperGenericsTest.java | 71 ++++++++++++++++++--
4 files changed, 150 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/8841d755/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 d8be3df..9d9619a 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
@@ -18,9 +18,17 @@
*/
package org.apache.johnzon.mapper.access;
+import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import static java.util.Arrays.asList;
+
// handle some specific types
public abstract class BaseAccessMode implements AccessMode {
private final Map<Class<?>, String[]> fieldsToRemove = new HashMap<Class<?>, String[]>();
@@ -58,4 +66,45 @@ public abstract class BaseAccessMode implements AccessMode {
}
return delegate;
}
+
+ protected Type fixType(final Class<?> clazz, final Type type) { // to enhance
+ if (TypeVariable.class.isInstance(type)) { // we need to handle it on deserialization side, not needed on serialization side
+ return fixTypeVariable(clazz, type);
+ }
+ if (ParameterizedType.class.isInstance(type)) {
+ final ParameterizedType pt = ParameterizedType.class.cast(type);
+ final Type[] actualTypeArguments = pt.getActualTypeArguments();
+ if (actualTypeArguments.length == 1 && Class.class.isInstance(pt.getRawType())
+ && Collection.class.isAssignableFrom(Class.class.cast(pt.getRawType()))
+ && Class.class.cast(pt.getRawType()).getName().startsWith("java.util.")
+ && TypeVariable.class.isInstance(actualTypeArguments[0])) {
+ return new JohnzonParameterizedType(pt.getRawType(), fixTypeVariable(clazz, actualTypeArguments[0]));
+ } else if (actualTypeArguments.length == 2 && Class.class.isInstance(pt.getRawType())
+ && Map.class.isAssignableFrom(Class.class.cast(pt.getRawType()))
+ && Class.class.cast(pt.getRawType()).getName().startsWith("java.util.")
+ && TypeVariable.class.isInstance(actualTypeArguments[1])) {
+ return new JohnzonParameterizedType(pt.getRawType(), actualTypeArguments[0], fixTypeVariable(clazz, actualTypeArguments[1]));
+ }
+ }
+ return type;
+ }
+
+ private Type fixTypeVariable(final Class<?> clazz, final Type type) {
+ final TypeVariable typeVariable = TypeVariable.class.cast(type);
+ if (typeVariable.getGenericDeclaration() == clazz.getSuperclass()) {
+ // try to match generic
+ final TypeVariable<? extends Class<?>>[] typeParameters = clazz.getSuperclass().getTypeParameters();
+ final int idx = asList(typeParameters).indexOf(typeVariable);
+ if (idx >= 0) {
+ final Type genParent = clazz.getGenericSuperclass();
+ if (ParameterizedType.class.isInstance(genParent)) {
+ final ParameterizedType pt = ParameterizedType.class.cast(genParent);
+ if (pt.getActualTypeArguments().length == typeParameters.length) {
+ return pt.getActualTypeArguments()[idx];
+ }
+ }
+ }
+ }
+ return type;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/8841d755/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 fb85a69..3f1b54c 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
@@ -38,7 +38,8 @@ public class FieldAccessMode extends BaseAccessMode {
continue;
}
- readers.put(extractKey(f.getValue(), key), new FieldReader(f.getValue()));
+ final Field field = f.getValue();
+ readers.put(extractKey(field, key), new FieldReader(field, fixType(clazz, field.getGenericType())));
}
return readers;
}
@@ -51,7 +52,9 @@ public class FieldAccessMode extends BaseAccessMode {
if (isIgnored(key)) {
continue;
}
- writers.put(extractKey(f.getValue(), key), new FieldWriter(f.getValue()));
+
+ final Field field = f.getValue();
+ writers.put(extractKey(field, key), new FieldWriter(field, fixType(clazz, field.getGenericType())));
}
return writers;
}
@@ -86,17 +89,19 @@ public class FieldAccessMode extends BaseAccessMode {
protected static abstract class FieldDecoratedType implements DecoratedType {
protected final Field field;
+ protected final Type type;
- public FieldDecoratedType(final Field field) {
+ public FieldDecoratedType(final Field field, final Type type) {
this.field = field;
if (!field.isAccessible()) {
this.field.setAccessible(true);
}
+ this.type = type;
}
@Override
public Type getType() {
- return field.getGenericType();
+ return type;
}
@Override
@@ -106,8 +111,8 @@ public class FieldAccessMode extends BaseAccessMode {
}
public static class FieldWriter extends FieldDecoratedType implements Writer {
- public FieldWriter(final Field field) {
- super(field);
+ public FieldWriter(final Field field, final Type type) {
+ super(field, type);
}
@Override
@@ -121,8 +126,8 @@ public class FieldAccessMode extends BaseAccessMode {
}
public static class FieldReader extends FieldDecoratedType implements Reader {
- public FieldReader(final Field field) {
- super(field);
+ public FieldReader(final Field field, final Type type) {
+ super(field, type);
}
@Override
@@ -133,5 +138,10 @@ public class FieldAccessMode extends BaseAccessMode {
throw new MapperException(e);
}
}
+
+ @Override
+ public Type getType() {
+ return type;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/8841d755/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
index d9cee8a..69f1af5 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
@@ -48,7 +48,7 @@ public class MethodAccessMode extends BaseAccessMode {
if (isIgnored(descriptor.getName())) {
continue;
}
- readers.put(extractKey(descriptor), new MethodReader(readMethod));
+ readers.put(extractKey(descriptor), new MethodReader(readMethod, fixType(clazz, readMethod.getGenericReturnType())));
}
}
return readers;
@@ -64,11 +64,12 @@ public class MethodAccessMode extends BaseAccessMode {
}
final Method writeMethod = descriptor.getWriteMethod();
if (writeMethod != null) {
- writers.put(extractKey(descriptor), new MethodWriter(writeMethod));
+ writers.put(extractKey(descriptor), new MethodWriter(writeMethod, fixType(clazz, writeMethod.getGenericParameterTypes()[0])));
} else if (supportGetterAsWritter
&& Collection.class.isAssignableFrom(descriptor.getPropertyType())
&& descriptor.getReadMethod() != null) {
- writers.put(extractKey(descriptor), new MethodGetterAsWriter(descriptor.getReadMethod()));
+ final Method readMethod = descriptor.getReadMethod();
+ writers.put(extractKey(descriptor), new MethodGetterAsWriter(readMethod, fixType(clazz, readMethod.getGenericReturnType())));
}
}
return writers;
@@ -95,12 +96,19 @@ public class MethodAccessMode extends BaseAccessMode {
protected static abstract class MethodDecoratedType implements DecoratedType {
protected final Method method;
+ protected final Type type;
- public MethodDecoratedType(final Method method) {
+ public MethodDecoratedType(final Method method, final Type type) {
this.method = method;
if (!method.isAccessible()) {
method.setAccessible(true);
}
+ this.type = type;
+ }
+
+ @Override
+ public Type getType() {
+ return type;
}
@Override
@@ -110,13 +118,8 @@ public class MethodAccessMode extends BaseAccessMode {
}
public static class MethodWriter extends MethodDecoratedType implements Writer {
- public MethodWriter(final Method method) {
- super(method);
- }
-
- @Override
- public Type getType() {
- return method.getGenericParameterTypes()[0];
+ public MethodWriter(final Method method, final Type type) {
+ super(method, type);
}
@Override
@@ -130,13 +133,8 @@ public class MethodAccessMode extends BaseAccessMode {
}
public static class MethodReader extends MethodDecoratedType implements Reader {
- public MethodReader(final Method method) {
- super(method);
- }
-
- @Override
- public Type getType() {
- return method.getGenericReturnType();
+ public MethodReader(final Method method, final Type type) {
+ super(method, type);
}
@Override
@@ -150,8 +148,8 @@ public class MethodAccessMode extends BaseAccessMode {
}
private class MethodGetterAsWriter extends MethodReader implements Writer {
- public MethodGetterAsWriter(final Method readMethod) {
- super(readMethod);
+ public MethodGetterAsWriter(final Method readMethod, final Type type) {
+ super(readMethod, type);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/8841d755/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperGenericsTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperGenericsTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperGenericsTest.java
index 7e6f30d..42245fb 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperGenericsTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperGenericsTest.java
@@ -19,41 +19,59 @@
package org.apache.johnzon.mapper;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import java.io.StringReader;
import java.util.List;
import java.util.Map;
+import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
public class MapperGenericsTest {
+ @Parameterized.Parameter
+ public String accessMode;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<String> modes() {
+ return asList("field", "method", "both", "strict-method");
+ }
+
@Test
public void base() {
- final Mapper mapper = new MapperBuilder().setAccessModeName("field").build();
+ final Mapper mapper = new MapperBuilder().setAccessModeName(accessMode).build();
final Foo foo = new Foo();
foo.name = "n";
final Concrete concrete = new Concrete();
concrete.value = foo;
- assertEquals("{\"value\":{\"name\":\"n\"}}", mapper.writeObjectAsString(concrete));
+ final String asString = mapper.writeObjectAsString(concrete);
+ assertEquals("{\"value\":{\"name\":\"n\"}}", asString);
+ assertEquals("n", Concrete.class.cast(mapper.readObject(new StringReader(asString), Concrete.class)).getValue().name);
}
@Test
public void list() {
- final Mapper mapper = new MapperBuilder().setAccessModeName("field").build();
+ final Mapper mapper = new MapperBuilder().setAccessModeName(accessMode).build();
final Foo foo = new Foo();
foo.name = "n";
final ConcreteList concrete = new ConcreteList();
concrete.value = singletonList(foo);
- assertEquals("{\"value\":[{\"name\":\"n\"}]}", mapper.writeObjectAsString(concrete));
+ final String asString = mapper.writeObjectAsString(concrete);
+ assertEquals("{\"value\":[{\"name\":\"n\"}]}", asString);
+ assertEquals("n", ConcreteList.class.cast(mapper.readObject(new StringReader(asString), ConcreteList.class)).getValue().iterator().next().name);
}
@Test
public void map() {
- final Mapper mapper = new MapperBuilder().setAccessModeName("field").build();
+ final Mapper mapper = new MapperBuilder().setAccessModeName(accessMode).build();
final Foo foo = new Foo();
foo.name = "n";
@@ -61,12 +79,18 @@ public class MapperGenericsTest {
final ConcreteMap concrete = new ConcreteMap();
concrete.value = singletonMap("k", foo);
- assertEquals("{\"value\":{\"k\":{\"name\":\"n\"}}}", mapper.writeObjectAsString(concrete));
+ final String asString = mapper.writeObjectAsString(concrete);
+ assertEquals("{\"value\":{\"k\":{\"name\":\"n\"}}}", asString);
+ assertEquals(concrete.value, ConcreteMap.class.cast(mapper.readObject(new StringReader(asString), ConcreteMap.class)).getValue());
}
public static abstract class Base<T> {
protected T value;
+ public void setValue(final T value) {
+ this.value = value;
+ }
+
public T getValue() {
return value;
}
@@ -75,6 +99,10 @@ public class MapperGenericsTest {
public static abstract class BaseList<T> {
protected List<T> value;
+ public void setValue(final List<T> value) {
+ this.value = value;
+ }
+
public List<T> getValue() {
return value;
}
@@ -83,6 +111,10 @@ public class MapperGenericsTest {
public static abstract class BaseMap<T> {
protected Map<String, T> value;
+ public void setValue(final Map<String, T> value) {
+ this.value = value;
+ }
+
public Map<String, T> getValue() {
return value;
}
@@ -99,5 +131,32 @@ public class MapperGenericsTest {
public static class Foo {
private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Foo foo = (Foo) o;
+ return name.equals(foo.name);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
}
}