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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user