Polishing for full type information on RepositoryMetadata.

Avoid leaking internals from TypeInformation by exposing a ….toTypeDescriptor() method in TypeInformation directly. This causes the ResolvableType handling to become an implementation detail within ClassTypeInformation and avoid client code to manually deal with both ResolvableType and TypeDescriptor creation.

Changed MethodLookups back to use the resolved domain types as the advanced generics resolutions seems not to be needed here and we can avoid

Fixes #2518.
This commit is contained in:
Oliver Drotbohm
2022-03-29 18:09:43 +02:00
parent 58ed9ce211
commit 3e9451c939
12 changed files with 117 additions and 109 deletions

View File

@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;
@@ -55,6 +56,7 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
}
private final Class<S> type;
private final Lazy<TypeDescriptor> descriptor;
/**
* Simple factory method to easily create new instances of {@link ClassTypeInformation}.
@@ -89,8 +91,11 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
* @param type
*/
ClassTypeInformation(Class<S> type) {
super(type, getTypeVariableMap(type));
this.type = type;
this.descriptor = Lazy.of(() -> TypeDescriptor.valueOf(type));
}
/**
@@ -152,6 +157,11 @@ public class ClassTypeInformation<S> extends TypeDiscoverer<S> {
return (TypeInformation<? extends S>) type;
}
@Override
public TypeDescriptor toTypeDescriptor() {
return descriptor.get();
}
@Override
public String toString() {
return type.getName();

View File

@@ -19,6 +19,8 @@ import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Map;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
@@ -29,6 +31,7 @@ import org.springframework.lang.Nullable;
public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S> {
private final TypeDiscoverer<?> parent;
private final Lazy<TypeDescriptor> descriptor;
private int hashCode;
/**
@@ -44,7 +47,14 @@ public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
super(type, map);
this.parent = parent;
this.descriptor = Lazy.of(() -> new TypeDescriptor(toResolvableType(), null, null));
}
@Override
public TypeDescriptor toTypeDescriptor() {
return descriptor.get();
}
@Override
@@ -57,6 +67,11 @@ public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S
return super.createInfo(fieldType);
}
@Override
protected ResolvableType toResolvableType() {
return ResolvableType.forType(getType(), parent.toResolvableType());
}
@Override
public boolean equals(@Nullable Object obj) {
@@ -80,7 +95,7 @@ public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S
public int hashCode() {
if (this.hashCode == 0) {
this.hashCode = super.hashCode() + 31 * parent.hashCode();
this.hashCode = super.hashCode() + (31 * parent.hashCode());
}
return this.hashCode;

View File

@@ -25,21 +25,14 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
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.Optional;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.springframework.beans.BeanUtils;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -112,7 +105,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
this.componentType = Lazy.of(this::doGetComponentType);
this.valueType = Lazy.of(this::doGetMapValueType);
this.typeVariableMap = typeVariableMap;
this.hashCode = 17 + 31 * type.hashCode() + 31 * typeVariableMap.hashCode();
this.hashCode = 17 + (31 * type.hashCode()) + (31 * typeVariableMap.hashCode());
}
/**
@@ -291,18 +284,14 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
return parameterTypes.length == 0 ? null : parameterTypes[0];
}
@Override
public Class<S> getType() {
return resolvedType.get();
}
@Override
public Type getGenericType() {
return type;
}
@Override
public TypeInformation<?> getGenericTypeInformation() {
return createInfo(type);
public TypeDescriptor toTypeDescriptor() {
return new TypeDescriptor(toResolvableType(), getType(), null);
}
@Override
@@ -499,6 +488,10 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
return getSuperTypeWithin(MAP_TYPES);
}
protected ResolvableType toResolvableType() {
return ResolvableType.forType(type);
}
@Override
public boolean equals(@Nullable Object obj) {
@@ -656,7 +649,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(typeInformation);
result = 31 * result + ObjectUtils.nullSafeHashCode(typeParameters);
result = (31 * result) + ObjectUtils.nullSafeHashCode(typeParameters);
return result;
}
}

View File

@@ -17,9 +17,9 @@ package org.springframework.data.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
/**
@@ -150,15 +150,6 @@ public interface TypeInformation<S> {
* @return
*/
Class<S> getType();
/**
* Returns the type of the property with all resolvable generics applied
*
* @return
*/
default Type getGenericType() {
return getType();
}
/**
* Returns the user type of the property if proxied.
@@ -181,13 +172,6 @@ public interface TypeInformation<S> {
*/
ClassTypeInformation<?> getRawTypeInformation();
/**
* Returns a {@link TypeInformation} to represent the {@link TypeInformation} of the type of the current instance with all the generics parameters resolved.
*
* @return
*/
TypeInformation<?> getGenericTypeInformation();
/**
* Transparently returns the {@link java.util.Map} value type if the type is a {@link java.util.Map}, returns the
* component type if the type {@link #isCollectionLike()} or the simple type if none of this applies.
@@ -305,4 +289,11 @@ public interface TypeInformation<S> {
return !type.equals(getType()) && type.isAssignableFrom(getType());
}
/**
* Returns the {@link TypeDescriptor} equivalent of this {@link TypeInformation}.
*
* @return will never be {@literal null}.
* @since 2.7
*/
TypeDescriptor toTypeDescriptor();
}

View File

@@ -19,6 +19,7 @@ import static org.springframework.util.ObjectUtils.*;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -33,6 +34,7 @@ import org.springframework.util.Assert;
class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
private final TypeVariable<?> variable;
private final Lazy<List<TypeInformation<?>>> parameters;
/**
* Creates a new {@link TypeVariableTypeInformation} for the given {@link TypeVariable} owning {@link Type} and parent
@@ -49,11 +51,18 @@ class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
Assert.notNull(variable, "TypeVariable must not be null!");
this.variable = variable;
this.parameters = Lazy.of(() -> {
return createInfo(getTypeVariableMap().getOrDefault(variable, Object.class)).getTypeArguments();
});
}
/*
* (non-Javadoc)
* @see org.springframework.data.util.TypeDiscoverer#getTypeArguments()
*/
@Override
public TypeInformation<?> getGenericTypeInformation() {
return createInfo(getTypeVariableMap().getOrDefault(variable, Object.class));
public List<TypeInformation<?>> getTypeArguments() {
return parameters.get();
}
@Override