Browse Source

DATACMNS-590 - Fixed calculation of nested generics in ParentTypeAwareTypeInformation.

So far, the lookup of the type variable map was preferring the type variable maps detected on parent types in nested structures. This caused the concrete type variables in nested types not being considered correctly which caused the type resolution to fall back to the generic bounds.

We now accumulate the type variable maps to avoid having to lookup a certain map in the nesting hierarchy. The core fix is in ParentTypeAwareTypeInformation's constructor and mergeMaps(…) respectively. Simplified the handling of type variable maps and made proper use of generics throughout the class hierarchy.
pull/103/head
Oliver Gierke 11 years ago
parent
commit
ac73720668
  1. 24
      src/main/java/org/springframework/data/util/ClassTypeInformation.java
  2. 14
      src/main/java/org/springframework/data/util/GenericArrayTypeInformation.java
  3. 13
      src/main/java/org/springframework/data/util/ParameterizedTypeInformation.java
  4. 28
      src/main/java/org/springframework/data/util/ParentTypeAwareTypeInformation.java
  5. 30
      src/main/java/org/springframework/data/util/TypeDiscoverer.java
  6. 5
      src/main/java/org/springframework/data/util/TypeVariableTypeInformation.java
  7. 36
      src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java
  8. 23
      src/test/java/org/springframework/data/util/ParameterizedTypeUnitTests.java
  9. 49
      src/test/java/org/springframework/data/util/TypeDiscovererUnitTests.java

24
src/main/java/org/springframework/data/util/ClassTypeInformation.java

@ -23,8 +23,10 @@ import java.lang.reflect.TypeVariable; @@ -23,8 +23,10 @@ import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
@ -98,12 +100,26 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> { @@ -98,12 +100,26 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
* @param type
*/
ClassTypeInformation(Class<S> type) {
this(type, GenericTypeResolver.getTypeVariableMap(type));
super(ClassUtils.getUserClass(type), getTypeVariableMap(type));
this.type = type;
}
ClassTypeInformation(Class<S> type, Map<TypeVariable, Type> typeVariableMap) {
super(ClassUtils.getUserClass(type), typeVariableMap);
this.type = type;
/**
* Little helper to allow us to create a generified map, actually just to satisfy the compiler.
*
* @param type must not be {@literal null}.
* @return
*/
private static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> type) {
Map<TypeVariable, Type> source = GenericTypeResolver.getTypeVariableMap(type);
Map<TypeVariable<?>, Type> map = new HashMap<TypeVariable<?>, Type>(source.size());
for (Entry<TypeVariable, Type> entry : source.entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
/*

14
src/main/java/org/springframework/data/util/GenericArrayTypeInformation.java

@ -18,6 +18,8 @@ package org.springframework.data.util; @@ -18,6 +18,8 @@ package org.springframework.data.util;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
/**
* Special {@link TypeDiscoverer} handling {@link GenericArrayType}s.
@ -26,18 +28,20 @@ import java.lang.reflect.Type; @@ -26,18 +28,20 @@ import java.lang.reflect.Type;
*/
class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
private GenericArrayType type;
private final GenericArrayType type;
/**
* Creates a new {@link GenericArrayTypeInformation} for the given {@link GenericArrayTypeInformation} and
* {@link TypeDiscoverer}.
*
* @param type
* @param parent
* @param type must not be {@literal null}.
* @param parent must not be {@literal null}.
* @param typeVariableMap must not be {@literal null}.
*/
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent) {
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent,
Map<TypeVariable<?>, Type> typeVariableMap) {
super(type, parent, parent.getTypeVariableMap());
super(type, parent, typeVariableMap);
this.type = type;
}

13
src/main/java/org/springframework/data/util/ParameterizedTypeInformation.java

@ -17,6 +17,7 @@ package org.springframework.data.util; @@ -17,6 +17,7 @@ package org.springframework.data.util;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@ -24,7 +25,6 @@ import java.util.List; @@ -24,7 +25,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.core.GenericTypeResolver;
import org.springframework.util.StringUtils;
/**
@ -44,8 +44,10 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> @@ -44,8 +44,10 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
* @param type must not be {@literal null}
* @param parent must not be {@literal null}
*/
public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> parent) {
super(type, parent, null);
public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> parent,
Map<TypeVariable<?>, Type> typeVariableMap) {
super(type, parent, typeVariableMap);
this.type = type;
}
@ -72,8 +74,11 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> @@ -72,8 +74,11 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
supertypes.addAll(Arrays.asList(rawType.getGenericInterfaces()));
for (Type supertype : supertypes) {
Class<?> rawSuperType = GenericTypeResolver.resolveType(supertype, getTypeVariableMap());
Class<?> rawSuperType = resolveType(supertype);
if (Map.class.isAssignableFrom(rawSuperType)) {
ParameterizedType parameterizedSupertype = (ParameterizedType) supertype;
Type[] arguments = parameterizedSupertype.getActualTypeArguments();
return createInfo(arguments[1]);

28
src/main/java/org/springframework/data/util/ParentTypeAwareTypeInformation.java

@ -17,6 +17,7 @@ package org.springframework.data.util; @@ -17,6 +17,7 @@ package org.springframework.data.util;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
import org.springframework.util.ObjectUtils;
@ -33,27 +34,30 @@ public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S @@ -33,27 +34,30 @@ public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S
/**
* Creates a new {@link ParentTypeAwareTypeInformation}.
*
* @param type
* @param parent
* @param map
* @param type must not be {@literal null}.
* @param parent must not be {@literal null}.
* @param map must not be {@literal null}.
*/
@SuppressWarnings("rawtypes")
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable, Type> map) {
super(type, map);
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
super(type, mergeMaps(parent, map));
this.parent = parent;
}
/**
* Considers the parent's type variable map before invoking the super class method.
* Merges the type variable maps of the given parent with the new map.
*
* @param parent must not be {@literal null}.
* @param map must not be {@literal null}.
* @return
*/
@Override
@SuppressWarnings("rawtypes")
protected Map<TypeVariable, Type> getTypeVariableMap() {
return parent == null ? super.getTypeVariableMap() : parent.getTypeVariableMap();
private static Map<TypeVariable<?>, Type> mergeMaps(TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
Map<TypeVariable<?>, Type> typeVariableMap = new HashMap<TypeVariable<?>, Type>();
typeVariableMap.putAll(map);
typeVariableMap.putAll(parent.getTypeVariableMap());
return typeVariableMap;
}
/*

30
src/main/java/org/springframework/data/util/TypeDiscoverer.java

@ -30,6 +30,7 @@ import java.util.ArrayList; @@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -47,7 +48,7 @@ import org.springframework.util.ReflectionUtils; @@ -47,7 +48,7 @@ import org.springframework.util.ReflectionUtils;
class TypeDiscoverer<S> implements TypeInformation<S> {
private final Type type;
@SuppressWarnings("rawtypes") private final Map<TypeVariable, Type> typeVariableMap;
private final Map<TypeVariable<?>, Type> typeVariableMap;
private final Map<String, TypeInformation<?>> fieldTypes = new ConcurrentHashMap<String, TypeInformation<?>>();
private Class<S> resolvedType;
@ -55,25 +56,24 @@ class TypeDiscoverer<S> implements TypeInformation<S> { @@ -55,25 +56,24 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
/**
* Creates a ne {@link TypeDiscoverer} for the given type, type variable map and parent.
*
* @param type must not be null.
* @param typeVariableMap
* @param type must not be {@literal null}.
* @param typeVariableMap must not be {@literal null}.
*/
@SuppressWarnings("rawtypes")
protected TypeDiscoverer(Type type, Map<TypeVariable, Type> typeVariableMap) {
protected TypeDiscoverer(Type type, Map<TypeVariable<?>, Type> typeVariableMap) {
Assert.notNull(type);
Assert.notNull(typeVariableMap);
this.type = type;
this.typeVariableMap = typeVariableMap;
}
/**
* Returns the type variable map. Will traverse the parents up to the root on and use it's map.
* Returns the type variable map.
*
* @return
*/
@SuppressWarnings("rawtypes")
protected Map<TypeVariable, Type> getTypeVariableMap() {
protected Map<TypeVariable<?>, Type> getTypeVariableMap() {
return typeVariableMap;
}
@ -98,7 +98,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> { @@ -98,7 +98,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
if (fieldType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
return new ParameterizedTypeInformation(parameterizedType, this);
return new ParameterizedTypeInformation(parameterizedType, this, variableMap);
}
if (fieldType instanceof TypeVariable) {
@ -107,7 +107,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> { @@ -107,7 +107,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
}
if (fieldType instanceof GenericArrayType) {
return new GenericArrayTypeInformation((GenericArrayType) fieldType, this);
return new GenericArrayTypeInformation((GenericArrayType) fieldType, this, variableMap);
}
if (fieldType instanceof WildcardType) {
@ -135,9 +135,13 @@ class TypeDiscoverer<S> implements TypeInformation<S> { @@ -135,9 +135,13 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
* @param type
* @return
*/
@SuppressWarnings("unchecked")
@SuppressWarnings({ "unchecked", "rawtypes" })
protected Class<S> resolveType(Type type) {
return (Class<S>) GenericTypeResolver.resolveType(type, getTypeVariableMap());
Map<TypeVariable, Type> map = new HashMap<TypeVariable, Type>();
map.putAll(getTypeVariableMap());
return (Class<S>) GenericTypeResolver.resolveType(type, map);
}
/*

5
src/main/java/org/springframework/data/util/TypeVariableTypeInformation.java

@ -43,11 +43,10 @@ class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> { @@ -43,11 +43,10 @@ class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
* @param owningType must not be {@literal null}
* @param parent
*/
@SuppressWarnings("rawtypes")
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent,
Map<TypeVariable, Type> map) {
Map<TypeVariable<?>, Type> typeVariableMap) {
super(variable, parent, map);
super(variable, parent, typeVariableMap);
Assert.notNull(variable);
this.variable = variable;
this.owningType = owningType;

36
src/test/java/org/springframework/data/util/ClassTypeInformationUnitTests.java

@ -93,7 +93,7 @@ public class ClassTypeInformationUnitTests { @@ -93,7 +93,7 @@ public class ClassTypeInformationUnitTests {
TypeInformation<StringCollectionContainer> information = ClassTypeInformation.from(StringCollectionContainer.class);
TypeInformation<?> property = information.getProperty("array");
assertEquals(property.getComponentType().getType(), String.class);
assertThat(property.getComponentType().getType(), is((Object) String.class));
Class<?> type = property.getType();
assertEquals(String[].class, type);
@ -327,6 +327,20 @@ public class ClassTypeInformationUnitTests { @@ -327,6 +327,20 @@ public class ClassTypeInformationUnitTests {
is("org.springframework.data.util.ClassTypeInformationUnitTests$SpecialPerson"));
}
/**
* @see DATACMNS-590
*/
@Test
public void resolvesNestedGenericsToConcreteType() {
ClassTypeInformation<ConcreteRoot> rootType = from(ConcreteRoot.class);
TypeInformation<?> subsPropertyType = rootType.getProperty("subs");
TypeInformation<?> subsElementType = subsPropertyType.getActualType();
TypeInformation<?> subSubType = subsElementType.getProperty("subSub");
assertThat(subSubType.getType(), is((Object) ConcreteSubSub.class));
}
static class StringMapContainer extends MapContainer<String> {
}
@ -461,4 +475,24 @@ public class ClassTypeInformationUnitTests { @@ -461,4 +475,24 @@ public class ClassTypeInformationUnitTests {
SortedMap<String, ? extends SortedMap<String, List<Person>>> seriously;
}
// DATACMNS-590
static abstract class GenericRoot<T extends GenericSub<?>> {
List<T> subs;
}
static abstract class GenericSub<T extends GenericSubSub> {
T subSub;
}
static abstract class GenericSubSub {}
static class ConcreteRoot extends GenericRoot<ConcreteSub> {}
static class ConcreteSub extends GenericSub<ConcreteSubSub> {}
static class ConcreteSubSub extends GenericSubSub {
String content;
}
}

23
src/test/java/org/springframework/data/util/ParameterizedTypeUnitTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,8 +22,11 @@ import static org.springframework.data.util.ClassTypeInformation.*; @@ -22,8 +22,11 @@ import static org.springframework.data.util.ClassTypeInformation.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
@ -39,6 +42,8 @@ import org.mockito.runners.MockitoJUnitRunner; @@ -39,6 +42,8 @@ import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ParameterizedTypeUnitTests {
static final Map<TypeVariable<?>, Type> EMPTY_MAP = Collections.emptyMap();
@Mock ParameterizedType one;
@Before
@ -49,22 +54,22 @@ public class ParameterizedTypeUnitTests { @@ -49,22 +54,22 @@ public class ParameterizedTypeUnitTests {
@Test
public void considersTypeInformationsWithDifferingParentsNotEqual() {
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, null);
TypeDiscoverer<Object> objectParent = new TypeDiscoverer<Object>(Object.class, null);
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, EMPTY_MAP);
TypeDiscoverer<Object> objectParent = new TypeDiscoverer<Object>(Object.class, EMPTY_MAP);
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(one, stringParent);
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(one, objectParent);
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(one, stringParent, EMPTY_MAP);
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(one, objectParent, EMPTY_MAP);
assertFalse(first.equals(second));
assertThat(first, is(not(second)));
}
@Test
public void considersTypeInformationsWithSameParentsNotEqual() {
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, null);
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, EMPTY_MAP);
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(one, stringParent);
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(one, stringParent);
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(one, stringParent, EMPTY_MAP);
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(one, stringParent, EMPTY_MAP);
assertTrue(first.equals(second));
}

49
src/test/java/org/springframework/data/util/TypeDiscovererUnitTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2011-2012 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +17,13 @@ package org.springframework.data.util; @@ -17,11 +17,13 @@ package org.springframework.data.util;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.util.ClassTypeInformation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -39,13 +41,10 @@ import org.mockito.runners.MockitoJUnitRunner; @@ -39,13 +41,10 @@ import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class TypeDiscovererUnitTests {
@Mock
@SuppressWarnings("rawtypes")
Map<TypeVariable, Type> firstMap;
static final Map<TypeVariable<?>, Type> EMPTY_MAP = Collections.emptyMap();
@Mock
@SuppressWarnings("rawtypes")
Map<TypeVariable, Type> secondMap;
@Mock Map<TypeVariable<?>, Type> firstMap;
@Mock Map<TypeVariable<?>, Type> secondMap;
@Test(expected = IllegalArgumentException.class)
public void rejectsNullType() {
@ -55,8 +54,8 @@ public class TypeDiscovererUnitTests { @@ -55,8 +54,8 @@ public class TypeDiscovererUnitTests {
@Test
public void isNotEqualIfTypesDiffer() {
TypeDiscoverer<Object> objectTypeInfo = new TypeDiscoverer<Object>(Object.class, null);
TypeDiscoverer<String> stringTypeInfo = new TypeDiscoverer<String>(String.class, null);
TypeDiscoverer<Object> objectTypeInfo = new TypeDiscoverer<Object>(Object.class, EMPTY_MAP);
TypeDiscoverer<String> stringTypeInfo = new TypeDiscoverer<String>(String.class, EMPTY_MAP);
assertFalse(objectTypeInfo.equals(stringTypeInfo));
}
@ -75,37 +74,44 @@ public class TypeDiscovererUnitTests { @@ -75,37 +74,44 @@ public class TypeDiscovererUnitTests {
@Test
public void dealsWithTypesReferencingThemselves() {
TypeInformation<SelfReferencing> information = new ClassTypeInformation<SelfReferencing>(SelfReferencing.class);
TypeInformation<SelfReferencing> information = from(SelfReferencing.class);
TypeInformation<?> first = information.getProperty("parent").getMapValueType();
TypeInformation<?> second = first.getProperty("map").getMapValueType();
assertEquals(first, second);
}
@Test
public void dealsWithTypesReferencingThemselvesInAMap() {
TypeInformation<SelfReferencingMap> information = new ClassTypeInformation<SelfReferencingMap>(
SelfReferencingMap.class);
TypeInformation<SelfReferencingMap> information = from(SelfReferencingMap.class);
TypeInformation<?> mapValueType = information.getProperty("map").getMapValueType();
assertEquals(mapValueType, information);
}
@Test
public void returnsComponentAndValueTypesForMapExtensions() {
TypeInformation<?> discoverer = new TypeDiscoverer<Object>(CustomMap.class, null);
TypeInformation<?> discoverer = new TypeDiscoverer<Object>(CustomMap.class, EMPTY_MAP);
assertEquals(Locale.class, discoverer.getMapValueType().getType());
assertEquals(String.class, discoverer.getComponentType().getType());
}
@Test
public void returnsComponentTypeForCollectionExtension() {
TypeDiscoverer<CustomCollection> discoverer = new TypeDiscoverer<CustomCollection>(CustomCollection.class, null);
TypeDiscoverer<CustomCollection> discoverer = new TypeDiscoverer<CustomCollection>(CustomCollection.class, firstMap);
assertEquals(String.class, discoverer.getComponentType().getType());
}
@Test
public void returnsComponentTypeForArrays() {
TypeDiscoverer<String[]> discoverer = new TypeDiscoverer<String[]>(String[].class, null);
TypeDiscoverer<String[]> discoverer = new TypeDiscoverer<String[]>(String[].class, EMPTY_MAP);
assertEquals(String.class, discoverer.getComponentType().getType());
}
@ -117,9 +123,10 @@ public class TypeDiscovererUnitTests { @@ -117,9 +123,10 @@ public class TypeDiscovererUnitTests {
public void discoveresConstructorParameterTypesCorrectly() throws NoSuchMethodException, SecurityException {
TypeDiscoverer<GenericConstructors> discoverer = new TypeDiscoverer<GenericConstructors>(GenericConstructors.class,
null);
firstMap);
Constructor<GenericConstructors> constructor = GenericConstructors.class.getConstructor(List.class, Locale.class);
List<TypeInformation<?>> types = discoverer.getParameterTypes(constructor);
assertThat(types.size(), is(2));
assertThat(types.get(0).getType(), equalTo((Class) List.class));
assertThat(types.get(0).getComponentType().getType(), is(equalTo((Class) String.class)));
@ -128,7 +135,9 @@ public class TypeDiscovererUnitTests { @@ -128,7 +135,9 @@ public class TypeDiscovererUnitTests {
@Test
@SuppressWarnings("rawtypes")
public void returnsNullForComponentAndValueTypesForRawMaps() {
TypeDiscoverer<Map> discoverer = new TypeDiscoverer<Map>(Map.class, null);
TypeDiscoverer<Map> discoverer = new TypeDiscoverer<Map>(Map.class, EMPTY_MAP);
assertThat(discoverer.getComponentType(), is(nullValue()));
assertThat(discoverer.getMapValueType(), is(nullValue()));
}
@ -140,14 +149,16 @@ public class TypeDiscovererUnitTests { @@ -140,14 +149,16 @@ public class TypeDiscovererUnitTests {
@SuppressWarnings("rawtypes")
public void doesNotConsiderTypeImplementingIterableACollection() {
TypeDiscoverer<Person> discoverer = new TypeDiscoverer<Person>(Person.class, null);
TypeInformation reference = ClassTypeInformation.from(Address.class);
TypeDiscoverer<Person> discoverer = new TypeDiscoverer<Person>(Person.class, EMPTY_MAP);
TypeInformation reference = from(Address.class);
TypeInformation<?> addresses = discoverer.getProperty("addresses");
assertThat(addresses.isCollectionLike(), is(false));
assertThat(addresses.getComponentType(), is(reference));
TypeInformation<?> adressIterable = discoverer.getProperty("addressIterable");
assertThat(adressIterable.isCollectionLike(), is(true));
assertThat(adressIterable.getComponentType(), is(reference));
}

Loading…
Cancel
Save