DATACMNS-88 - Map value types are now resolve correctly for generic types extending Map.
Extracted base ParentTypeAwareTypeInformation class as base class for TypeInformations that need to consider the parent's type variable map.
This commit is contained in:
@@ -24,7 +24,7 @@ import java.lang.reflect.Type;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
class GenericArrayTypeInformation<S> extends ParameterizedTypeInformation<S> {
|
class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
|
||||||
|
|
||||||
private GenericArrayType type;
|
private GenericArrayType type;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ class GenericArrayTypeInformation<S> extends ParameterizedTypeInformation<S> {
|
|||||||
* @param parent
|
* @param parent
|
||||||
*/
|
*/
|
||||||
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent) {
|
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent) {
|
||||||
super(type, parent);
|
super(type, parent, parent.getTypeVariableMap());
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.util;
|
package org.springframework.data.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.lang.reflect.TypeVariable;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all types that include parameterization of some kind. Crucial as we have to take note of the parent
|
* Base class for all types that include parameterization of some kind. Crucial as we have to take note of the parent
|
||||||
@@ -28,9 +28,9 @@ import org.springframework.util.ObjectUtils;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
|
class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||||
|
|
||||||
private final TypeDiscoverer<?> parent;
|
private final ParameterizedType type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link ParameterizedTypeInformation} for the given {@link Type} and parent {@link TypeDiscoverer}.
|
* Creates a new {@link ParameterizedTypeInformation} for the given {@link Type} and parent {@link TypeDiscoverer}.
|
||||||
@@ -38,60 +38,40 @@ class ParameterizedTypeInformation<T> extends TypeDiscoverer<T> {
|
|||||||
* @param type must not be {@literal null}
|
* @param type must not be {@literal null}
|
||||||
* @param parent must not be {@literal null}
|
* @param parent must not be {@literal null}
|
||||||
*/
|
*/
|
||||||
public ParameterizedTypeInformation(Type type, TypeDiscoverer<?> parent) {
|
public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> parent) {
|
||||||
super(type, null);
|
super(type, parent, null);
|
||||||
Assert.notNull(parent);
|
this.type = type;
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Considers the parent's type variable map before invoking the super class method.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
protected Map<TypeVariable, Type> getTypeVariableMap() {
|
|
||||||
|
|
||||||
return parent != null ? parent.getTypeVariableMap() : super.getTypeVariableMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.util.TypeDiscoverer#createInfo(java.lang.reflect.Type)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected TypeInformation<?> createInfo(Type fieldType) {
|
|
||||||
if (parent.getType().equals(fieldType)) {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.createInfo(fieldType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.util.TypeDiscoverer#equals(java.lang.Object)
|
* @see org.springframework.data.util.TypeDiscoverer#getMapValueType()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public TypeInformation<?> getMapValueType() {
|
||||||
|
|
||||||
if (!super.equals(obj)) {
|
if (Map.class.equals(getType())) {
|
||||||
return false;
|
Type[] arguments = type.getActualTypeArguments();
|
||||||
|
return createInfo(arguments[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.getClass().equals(obj.getClass())) {
|
Class<?> rawType = getType();
|
||||||
return false;
|
|
||||||
|
Set<Type> supertypes = new HashSet<Type>();
|
||||||
|
supertypes.add(rawType.getGenericSuperclass());
|
||||||
|
supertypes.addAll(Arrays.asList(rawType.getGenericInterfaces()));
|
||||||
|
|
||||||
|
for (Type supertype : supertypes) {
|
||||||
|
Class<?> rawSuperType = GenericTypeResolver.resolveType(supertype, getTypeVariableMap());
|
||||||
|
if (Map.class.isAssignableFrom(rawSuperType)) {
|
||||||
|
ParameterizedType parameterizedSupertype = (ParameterizedType) supertype;
|
||||||
|
Type[] arguments = parameterizedSupertype.getActualTypeArguments();
|
||||||
|
return createInfo(arguments[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterizedTypeInformation<?> that = (ParameterizedTypeInformation<?>) obj;
|
return super.getMapValueType();
|
||||||
return this.parent == null ? that.parent == null : this.parent.equals(that.parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.util.TypeDiscoverer#hashCode()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return super.hashCode() + 31 * ObjectUtils.nullSafeHashCode(parent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package org.springframework.data.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for {@link TypeInformation} implementations that need parent type awareness.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S> {
|
||||||
|
|
||||||
|
private final TypeDiscoverer<?> parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ParentTypeAwareTypeInformation}.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* @param typeVariableMap
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable, Type> map) {
|
||||||
|
super(type, map);
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Considers the parent's type variable map before invoking the super class method.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
protected Map<TypeVariable, Type> getTypeVariableMap() {
|
||||||
|
return parent == null ? super.getTypeVariableMap() : parent.getTypeVariableMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.util.TypeDiscoverer#createInfo(java.lang.reflect.Type)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected TypeInformation<?> createInfo(Type fieldType) {
|
||||||
|
|
||||||
|
if (parent.getType().equals(fieldType)) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.createInfo(fieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.util.TypeDiscoverer#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.getClass().equals(obj.getClass())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParentTypeAwareTypeInformation<?> that = (ParentTypeAwareTypeInformation<?>) obj;
|
||||||
|
return this.parent == null ? that.parent == null : this.parent.equals(that.parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.util.TypeDiscoverer#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return super.hashCode() + 31 * ObjectUtils.nullSafeHashCode(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -88,6 +88,8 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
|||||||
if (fieldType instanceof Class) {
|
if (fieldType instanceof Class) {
|
||||||
return new ClassTypeInformation((Class<?>) fieldType);
|
return new ClassTypeInformation((Class<?>) fieldType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<TypeVariable, Type> variableMap = GenericTypeResolver.getTypeVariableMap(resolveType(fieldType));
|
||||||
|
|
||||||
if (fieldType instanceof ParameterizedType) {
|
if (fieldType instanceof ParameterizedType) {
|
||||||
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
|
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
|
||||||
@@ -96,7 +98,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
|||||||
|
|
||||||
if (fieldType instanceof TypeVariable) {
|
if (fieldType instanceof TypeVariable) {
|
||||||
TypeVariable<?> variable = (TypeVariable<?>) fieldType;
|
TypeVariable<?> variable = (TypeVariable<?>) fieldType;
|
||||||
return new TypeVariableTypeInformation(variable, type, this);
|
return new TypeVariableTypeInformation(variable, type, this, variableMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldType instanceof GenericArrayType) {
|
if (fieldType instanceof GenericArrayType) {
|
||||||
@@ -263,12 +265,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
|||||||
if (!isMap()) {
|
if (!isMap()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type instanceof ParameterizedType) {
|
|
||||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
|
||||||
return createInfo(parameterizedType.getActualTypeArguments()[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return getTypeArgument(getType(), Map.class, 1);
|
return getTypeArgument(getType(), Map.class, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static org.springframework.util.ObjectUtils.*;
|
|||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.lang.reflect.TypeVariable;
|
import java.lang.reflect.TypeVariable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
class TypeVariableTypeInformation<T> extends ParameterizedTypeInformation<T> {
|
class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||||
|
|
||||||
private final TypeVariable<?> variable;
|
private final TypeVariable<?> variable;
|
||||||
private final Type owningType;
|
private final Type owningType;
|
||||||
@@ -42,9 +43,9 @@ class TypeVariableTypeInformation<T> extends ParameterizedTypeInformation<T> {
|
|||||||
* @param owningType must not be {@literal null}
|
* @param owningType must not be {@literal null}
|
||||||
* @param parent
|
* @param parent
|
||||||
*/
|
*/
|
||||||
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent) {
|
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent, Map<TypeVariable, Type> map) {
|
||||||
|
|
||||||
super(variable, parent);
|
super(variable, parent, map);
|
||||||
Assert.notNull(variable);
|
Assert.notNull(variable);
|
||||||
this.variable = variable;
|
this.variable = variable;
|
||||||
this.owningType = owningType;
|
this.owningType = owningType;
|
||||||
|
|||||||
@@ -55,33 +55,40 @@ public class ClassTypeInformationUnitTests {
|
|||||||
TypeInformation<?> content = wrapper.getProperty("content");
|
TypeInformation<?> content = wrapper.getProperty("content");
|
||||||
|
|
||||||
assertEquals(String.class, content.getType());
|
assertEquals(String.class, content.getType());
|
||||||
assertEquals(String.class, discoverer.getProperty("wrapped").getProperty("content").getType());
|
assertEquals(String.class,
|
||||||
assertEquals(String.class, discoverer.getProperty("wrapped.content").getType());
|
discoverer.getProperty("wrapped").getProperty("content").getType());
|
||||||
|
assertEquals(String.class, discoverer.getProperty("wrapped.content")
|
||||||
|
.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public void discoversBoundType() {
|
public void discoversBoundType() {
|
||||||
|
|
||||||
TypeInformation<GenericTypeWithBound> information = ClassTypeInformation.from(GenericTypeWithBound.class);
|
TypeInformation<GenericTypeWithBound> information = ClassTypeInformation.from(
|
||||||
|
GenericTypeWithBound.class);
|
||||||
assertEquals(Person.class, information.getProperty("person").getType());
|
assertEquals(Person.class, information.getProperty("person").getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void discoversBoundTypeForSpecialization() {
|
public void discoversBoundTypeForSpecialization() {
|
||||||
|
|
||||||
TypeInformation<SpecialGenericTypeWithBound> information = ClassTypeInformation
|
TypeInformation<SpecialGenericTypeWithBound> information = ClassTypeInformation.from(
|
||||||
.from(SpecialGenericTypeWithBound.class);
|
SpecialGenericTypeWithBound.class);
|
||||||
assertEquals(SpecialPerson.class, information.getProperty("person").getType());
|
assertEquals(SpecialPerson.class, information.getProperty("person")
|
||||||
|
.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public void discoversBoundTypeForNested() {
|
public void discoversBoundTypeForNested() {
|
||||||
|
|
||||||
TypeInformation<AnotherGenericType> information = ClassTypeInformation.from(AnotherGenericType.class);
|
TypeInformation<AnotherGenericType> information = ClassTypeInformation.from(
|
||||||
assertEquals(GenericTypeWithBound.class, information.getProperty("nested").getType());
|
AnotherGenericType.class);
|
||||||
assertEquals(Person.class, information.getProperty("nested.person").getType());
|
assertEquals(GenericTypeWithBound.class, information.getProperty("nested")
|
||||||
|
.getType());
|
||||||
|
assertEquals(Person.class, information.getProperty("nested.person")
|
||||||
|
.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -118,25 +125,25 @@ public class ClassTypeInformationUnitTests {
|
|||||||
assertEquals(Map.class, map.getType());
|
assertEquals(Map.class, map.getType());
|
||||||
assertEquals(Calendar.class, map.getMapValueType().getType());
|
assertEquals(Calendar.class, map.getMapValueType().getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void typeInfoDoesNotEqualForGenericTypesWithDifferentParent() {
|
public void typeInfoDoesNotEqualForGenericTypesWithDifferentParent() {
|
||||||
|
|
||||||
TypeInformation<ConcreteWrapper> first = ClassTypeInformation.from(ConcreteWrapper.class);
|
TypeInformation<ConcreteWrapper> first = ClassTypeInformation.from(ConcreteWrapper.class);
|
||||||
TypeInformation<AnotherConcreteWrapper> second = ClassTypeInformation.from(AnotherConcreteWrapper.class);
|
TypeInformation<AnotherConcreteWrapper> second = ClassTypeInformation.from(AnotherConcreteWrapper.class);
|
||||||
|
|
||||||
assertFalse(first.getProperty("wrapped").equals(second.getProperty("wrapped")));
|
assertFalse(first.getProperty("wrapped").equals(second.getProperty("wrapped")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlesPropertyFieldMismatchCorrectly() {
|
public void handlesPropertyFieldMismatchCorrectly() {
|
||||||
|
|
||||||
TypeInformation<PropertyGetter> from = ClassTypeInformation.from(PropertyGetter.class);
|
TypeInformation<PropertyGetter> from = ClassTypeInformation.from(PropertyGetter.class);
|
||||||
|
|
||||||
TypeInformation<?> property = from.getProperty("_name");
|
TypeInformation<?> property = from.getProperty("_name");
|
||||||
assertThat(property, is(notNullValue()));
|
assertThat(property, is(notNullValue()));
|
||||||
assertThat(property.getType(), is(typeCompatibleWith(String.class)));
|
assertThat(property.getType(), is(typeCompatibleWith(String.class)));
|
||||||
|
|
||||||
property = from.getProperty("name");
|
property = from.getProperty("name");
|
||||||
assertThat(property, is(notNullValue()));
|
assertThat(property, is(notNullValue()));
|
||||||
assertThat(property.getType(), is(typeCompatibleWith(byte[].class)));
|
assertThat(property.getType(), is(typeCompatibleWith(byte[].class)));
|
||||||
@@ -203,7 +210,8 @@ public class ClassTypeInformationUnitTests {
|
|||||||
S nested;
|
S nested;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SpecialGenericTypeWithBound extends GenericTypeWithBound<SpecialPerson> {
|
static class SpecialGenericTypeWithBound extends
|
||||||
|
GenericTypeWithBound<SpecialPerson> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,14 +239,14 @@ public class ClassTypeInformationUnitTests {
|
|||||||
static class ConcreteWrapper extends GenericWrapper<String> {
|
static class ConcreteWrapper extends GenericWrapper<String> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AnotherConcreteWrapper extends GenericWrapper<Long> {
|
static class AnotherConcreteWrapper extends GenericWrapper<Long> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PropertyGetter {
|
static class PropertyGetter {
|
||||||
private String _name;
|
private String _name;
|
||||||
|
|
||||||
public byte[] getName() {
|
public byte[] getName() {
|
||||||
return _name.getBytes();
|
return _name.getBytes();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,25 +15,36 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.util;
|
package org.springframework.data.util;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link ParameterizedTypeInformation}.
|
* Unit tests for {@link ParameterizedTypeInformation}.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class ParameterizedTypeUnitTests {
|
public class ParameterizedTypeUnitTests {
|
||||||
|
|
||||||
|
@Mock ParameterizedType one, two;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void considersTypeInformationsWithDifferingParentsNotEqual() {
|
public void considersTypeInformationsWithDifferingParentsNotEqual() {
|
||||||
|
|
||||||
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, null);
|
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, null);
|
||||||
TypeDiscoverer<Object> objectParent = new TypeDiscoverer<Object>(Object.class, null);
|
TypeDiscoverer<Object> objectParent = new TypeDiscoverer<Object>(Object.class, null);
|
||||||
|
|
||||||
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(Object.class, stringParent);
|
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(one, stringParent);
|
||||||
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(Object.class, objectParent);
|
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(one, objectParent);
|
||||||
|
|
||||||
assertFalse(first.equals(second));
|
assertFalse(first.equals(second));
|
||||||
}
|
}
|
||||||
@@ -43,9 +54,40 @@ public class ParameterizedTypeUnitTests {
|
|||||||
|
|
||||||
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, null);
|
TypeDiscoverer<String> stringParent = new TypeDiscoverer<String>(String.class, null);
|
||||||
|
|
||||||
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(Object.class, stringParent);
|
ParameterizedTypeInformation<Object> first = new ParameterizedTypeInformation<Object>(one, stringParent);
|
||||||
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(Object.class, stringParent);
|
ParameterizedTypeInformation<Object> second = new ParameterizedTypeInformation<Object>(one, stringParent);
|
||||||
|
|
||||||
assertTrue(first.equals(second));
|
assertTrue(first.equals(second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DATACMNS-88
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void resolvesMapValueTypeCorrectly() {
|
||||||
|
|
||||||
|
TypeInformation<Foo> type = ClassTypeInformation.from(Foo.class);
|
||||||
|
TypeInformation<?> propertyType = type.getProperty("param");
|
||||||
|
assertThat(propertyType.getProperty("value").getType(), is(typeCompatibleWith(String.class)));
|
||||||
|
assertThat(propertyType.getMapValueType().getType(), is(typeCompatibleWith(String.class)));
|
||||||
|
|
||||||
|
propertyType = type.getProperty("param2");
|
||||||
|
assertThat(propertyType.getProperty("value").getType(), is(typeCompatibleWith(String.class)));
|
||||||
|
assertThat(propertyType.getMapValueType().getType(), is(typeCompatibleWith(Locale.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
class Localized<S> extends HashMap<Locale, S> {
|
||||||
|
S value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
class Localized2<S> extends HashMap<S, Locale> {
|
||||||
|
S value;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
Localized<String> param;
|
||||||
|
Localized2<String> param2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user