DATACMNS-594 - Fixed creation of type variable map to extend into detected bounds.

The initial setup of the type variable map now unfolds the detected types in the map to make sure we detect all type variables present in the current scope.

Added caching of component and map value TypeInformation instances to avoid repeated creation.
This commit is contained in:
Oliver Gierke
2014-11-14 16:34:31 +01:00
parent eac6fcaa8e
commit c5721cfc0c
5 changed files with 103 additions and 22 deletions

View File

@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -111,12 +112,29 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
* @return
*/
private static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> type) {
return getTypeVariableMap(type, new HashSet<Type>());
}
@SuppressWarnings("deprecation")
private static Map<TypeVariable<?>, Type> getTypeVariableMap(Class<?> type, Collection<Type> visited) {
if (visited.contains(type)) {
return Collections.emptyMap();
} else {
visited.add(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()) {
Type value = entry.getValue();
map.put(entry.getKey(), entry.getValue());
if (value instanceof Class) {
map.putAll(getTypeVariableMap((Class<?>) value, visited));
}
}
return map;

View File

@@ -57,10 +57,10 @@ class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#getComponentType()
* @see org.springframework.data.util.TypeDiscoverer#doGetComponentType()
*/
@Override
public TypeInformation<?> getComponentType() {
protected TypeInformation<?> doGetComponentType() {
Type componentType = type.getGenericComponentType();
return createInfo(componentType);

View File

@@ -36,7 +36,7 @@ import org.springframework.util.StringUtils;
class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
private final ParameterizedType type;
private TypeInformation<?> componentType;
private Boolean resolved;
/**
* Creates a new {@link ParameterizedTypeInformation} for the given {@link Type} and parent {@link TypeDiscoverer}.
@@ -51,12 +51,12 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
this.type = type;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#getMapValueType()
* @see org.springframework.data.util.TypeDiscoverer#doGetMapValueType()
*/
@Override
public TypeInformation<?> getMapValueType() {
protected TypeInformation<?> doGetMapValueType() {
if (Map.class.isAssignableFrom(getType())) {
@@ -141,18 +141,13 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
return true;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#getComponentType()
* @see org.springframework.data.util.TypeDiscoverer#doGetComponentType()
*/
@Override
public TypeInformation<?> getComponentType() {
if (componentType == null) {
this.componentType = createInfo(type.getActualTypeArguments()[0]);
}
return this.componentType;
protected TypeInformation<?> doGetComponentType() {
return createInfo(type.getActualTypeArguments()[0]);
}
/*
@@ -201,10 +196,14 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
private boolean isResolvedCompletely() {
if (resolved != null) {
return resolved;
}
Type[] types = type.getActualTypeArguments();
if (types.length == 0) {
return false;
return cacheAndReturn(false);
}
for (Type type : types) {
@@ -213,15 +212,21 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
if (info instanceof ParameterizedTypeInformation) {
if (!((ParameterizedTypeInformation<?>) info).isResolvedCompletely()) {
return false;
return cacheAndReturn(false);
}
}
if (!(info instanceof ClassTypeInformation)) {
return false;
return cacheAndReturn(false);
}
}
return true;
return cacheAndReturn(true);
}
private boolean cacheAndReturn(boolean resolved) {
this.resolved = resolved;
return resolved;
}
}

View File

@@ -51,6 +51,12 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
private final Map<TypeVariable<?>, Type> typeVariableMap;
private final Map<String, TypeInformation<?>> fieldTypes = new ConcurrentHashMap<String, TypeInformation<?>>();
private boolean componentTypeResolved = false;
private TypeInformation<?> componentType;
private boolean valueTypeResolved = false;
private TypeInformation<?> valueType;
private Class<S> resolvedType;
/**
@@ -83,7 +89,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
* @param fieldType
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" })
protected TypeInformation<?> createInfo(Type fieldType) {
if (fieldType.equals(this.type)) {
@@ -135,7 +141,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
* @param type
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })
protected Class<S> resolveType(Type type) {
Map<TypeVariable, Type> map = new HashMap<TypeVariable, Type>();
@@ -313,6 +319,16 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
*/
public TypeInformation<?> getMapValueType() {
if (!valueTypeResolved) {
this.valueType = doGetMapValueType();
this.valueTypeResolved = true;
}
return this.valueType;
}
protected TypeInformation<?> doGetMapValueType() {
if (isMap()) {
return getTypeArgument(Map.class, 1);
}
@@ -345,7 +361,17 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
* (non-Javadoc)
* @see org.springframework.data.util.TypeInformation#getComponentType()
*/
public TypeInformation<?> getComponentType() {
public final TypeInformation<?> getComponentType() {
if (!componentTypeResolved) {
this.componentType = doGetComponentType();
this.componentTypeResolved = true;
}
return this.componentType;
}
protected TypeInformation<?> doGetComponentType() {
Class<S> rawType = getType();