ResolvableType.forRawClass as a straight wrapper for Class.isAssignableFrom
Issue: SPR-12846
This commit is contained in:
@@ -561,7 +561,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {
|
public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException {
|
||||||
return isTypeMatch(name, ResolvableType.forClass(typeToMatch != null ? typeToMatch : Object.class));
|
return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -412,8 +412,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
@Override
|
@Override
|
||||||
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
|
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
|
||||||
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
|
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
|
||||||
return doGetBeanNamesForType(ResolvableType.forClass(type != null ? type : Object.class),
|
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
|
||||||
includeNonSingletons, allowEagerInit);
|
|
||||||
}
|
}
|
||||||
Map<Class<?>, String[]> cache =
|
Map<Class<?>, String[]> cache =
|
||||||
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
|
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
|
||||||
@@ -421,7 +420,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
if (resolvedBeanNames != null) {
|
if (resolvedBeanNames != null) {
|
||||||
return resolvedBeanNames;
|
return resolvedBeanNames;
|
||||||
}
|
}
|
||||||
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forClass(type), includeNonSingletons, allowEagerInit);
|
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
|
||||||
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
|
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
|
||||||
cache.put(type, resolvedBeanNames);
|
cache.put(type, resolvedBeanNames);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.beans.factory;
|
package org.springframework.beans.factory;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.security.AccessControlContext;
|
import java.security.AccessControlContext;
|
||||||
@@ -32,6 +33,7 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import javax.annotation.Priority;
|
import javax.annotation.Priority;
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
@@ -1669,13 +1671,21 @@ public class DefaultListableBeanFactoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetBeanNamesForTypeBeforeFactoryBeanCreation() {
|
public void testGetBeanNamesForTypeBeforeFactoryBeanCreation() {
|
||||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||||
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName()));
|
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
|
||||||
assertFalse(lbf.containsSingleton("factoryBean"));
|
assertFalse(lbf.containsSingleton("factoryBean"));
|
||||||
|
|
||||||
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
|
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
|
||||||
assertEquals(1, beanNames.length);
|
assertEquals(1, beanNames.length);
|
||||||
assertEquals("&factoryBean", beanNames[0]);
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
|
|
||||||
|
beanNames = lbf.getBeanNamesForType(Callable.class, false, false);
|
||||||
|
assertEquals(1, beanNames.length);
|
||||||
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
|
|
||||||
|
beanNames = lbf.getBeanNamesForType(RepositoryFactoryInformation.class, false, false);
|
||||||
|
assertEquals(1, beanNames.length);
|
||||||
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
|
|
||||||
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
|
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
|
||||||
assertEquals(1, beanNames.length);
|
assertEquals(1, beanNames.length);
|
||||||
assertEquals("&factoryBean", beanNames[0]);
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
@@ -1684,13 +1694,21 @@ public class DefaultListableBeanFactoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetBeanNamesForTypeAfterFactoryBeanCreation() {
|
public void testGetBeanNamesForTypeAfterFactoryBeanCreation() {
|
||||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||||
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class.getName()));
|
lbf.registerBeanDefinition("factoryBean", new RootBeanDefinition(FactoryBeanThatShouldntBeCalled.class));
|
||||||
lbf.getBean("&factoryBean");
|
lbf.getBean("&factoryBean");
|
||||||
|
|
||||||
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
|
String[] beanNames = lbf.getBeanNamesForType(Runnable.class, false, false);
|
||||||
assertEquals(1, beanNames.length);
|
assertEquals(1, beanNames.length);
|
||||||
assertEquals("&factoryBean", beanNames[0]);
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
|
|
||||||
|
beanNames = lbf.getBeanNamesForType(Callable.class, false, false);
|
||||||
|
assertEquals(1, beanNames.length);
|
||||||
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
|
|
||||||
|
beanNames = lbf.getBeanNamesForType(RepositoryFactoryInformation.class, false, false);
|
||||||
|
assertEquals(1, beanNames.length);
|
||||||
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
|
|
||||||
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
|
beanNames = lbf.getBeanNamesForType(FactoryBean.class, false, false);
|
||||||
assertEquals(1, beanNames.length);
|
assertEquals(1, beanNames.length);
|
||||||
assertEquals("&factoryBean", beanNames[0]);
|
assertEquals("&factoryBean", beanNames[0]);
|
||||||
@@ -2892,10 +2910,24 @@ public class DefaultListableBeanFactoryTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class FactoryBeanThatShouldntBeCalled implements FactoryBean<Object>, Runnable {
|
public interface Repository<T, ID extends Serializable> {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface RepositoryFactoryInformation<T, ID extends Serializable> {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static abstract class RepositoryFactoryBeanSupport<T extends Repository<S, ID>, S, ID extends Serializable>
|
||||||
|
implements RepositoryFactoryInformation<S, ID>, FactoryBean<T> {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class FactoryBeanThatShouldntBeCalled<T extends Repository<S, ID>, S, ID extends Serializable>
|
||||||
|
extends RepositoryFactoryBeanSupport<T, S, ID> implements Runnable, Callable<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public T getObject() {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2913,6 +2945,11 @@ public class DefaultListableBeanFactoryTests {
|
|||||||
public void run() {
|
public void run() {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T call() throws Exception {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* @see #forType(Type)
|
* @see #forType(Type)
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public final class ResolvableType implements Serializable {
|
public class ResolvableType implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code ResolvableType} returned when no value is available. {@code NONE} is used
|
* {@code ResolvableType} returned when no value is available. {@code NONE} is used
|
||||||
@@ -122,6 +122,17 @@ public final class ResolvableType implements Serializable {
|
|||||||
private ResolvableType[] generics;
|
private ResolvableType[] generics;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor used to create a new {@link ResolvableType} for cache key purposes.
|
||||||
|
*/
|
||||||
|
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) {
|
||||||
|
this.type = type;
|
||||||
|
this.typeProvider = typeProvider;
|
||||||
|
this.variableResolver = variableResolver;
|
||||||
|
this.componentType = null;
|
||||||
|
this.resolved = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor used to create a new {@link ResolvableType} for resolution purposes.
|
* Private constructor used to create a new {@link ResolvableType} for resolution purposes.
|
||||||
*/
|
*/
|
||||||
@@ -136,14 +147,16 @@ public final class ResolvableType implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor used to create a new {@link ResolvableType} for cache key purposes.
|
* Private constructor used to create a new {@link ResolvableType} on a {@link Class} basis.
|
||||||
|
* Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper.
|
||||||
|
* @since 4.2
|
||||||
*/
|
*/
|
||||||
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) {
|
private ResolvableType(Class<?> sourceClass) {
|
||||||
this.type = type;
|
this.resolved = (sourceClass != null ? sourceClass : Object.class);
|
||||||
this.typeProvider = typeProvider;
|
this.type = this.resolved;
|
||||||
this.variableResolver = variableResolver;
|
this.typeProvider = null;
|
||||||
|
this.variableResolver = null;
|
||||||
this.componentType = null;
|
this.componentType = null;
|
||||||
this.resolved = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -160,6 +173,9 @@ public final class ResolvableType implements Serializable {
|
|||||||
* otherwise {@code null}.
|
* otherwise {@code null}.
|
||||||
*/
|
*/
|
||||||
public Class<?> getRawClass() {
|
public Class<?> getRawClass() {
|
||||||
|
if (this.type == this.resolved) {
|
||||||
|
return this.resolved;
|
||||||
|
}
|
||||||
Type rawType = this.type;
|
Type rawType = this.type;
|
||||||
if (rawType instanceof ParameterizedType) {
|
if (rawType instanceof ParameterizedType) {
|
||||||
rawType = ((ParameterizedType) rawType).getRawType();
|
rawType = ((ParameterizedType) rawType).getRawType();
|
||||||
@@ -619,7 +635,7 @@ public final class ResolvableType implements Serializable {
|
|||||||
return EMPTY_TYPES_ARRAY;
|
return EMPTY_TYPES_ARRAY;
|
||||||
}
|
}
|
||||||
if (this.generics == null) {
|
if (this.generics == null) {
|
||||||
if (this.type instanceof Class<?>) {
|
if (this.type instanceof Class) {
|
||||||
Class<?> typeClass = (Class<?>) this.type;
|
Class<?> typeClass = (Class<?>) this.type;
|
||||||
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
|
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
|
||||||
}
|
}
|
||||||
@@ -712,7 +728,7 @@ public final class ResolvableType implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> resolveClass() {
|
private Class<?> resolveClass() {
|
||||||
if (this.type instanceof Class<?> || this.type == null) {
|
if (this.type instanceof Class || this.type == null) {
|
||||||
return (Class<?>) this.type;
|
return (Class<?>) this.type;
|
||||||
}
|
}
|
||||||
if (this.type instanceof GenericArrayType) {
|
if (this.type instanceof GenericArrayType) {
|
||||||
@@ -783,6 +799,66 @@ public final class ResolvableType implements Serializable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (this == other) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(other instanceof ResolvableType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ResolvableType otherType = (ResolvableType) other;
|
||||||
|
return (ObjectUtils.nullSafeEquals(this.type, otherType.type) &&
|
||||||
|
ObjectUtils.nullSafeEquals(getSource(), otherType.getSource()) &&
|
||||||
|
variableResolverSourceEquals(otherType.variableResolver) &&
|
||||||
|
ObjectUtils.nullSafeEquals(this.componentType, otherType.componentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hashCode = ObjectUtils.nullSafeHashCode(this.type);
|
||||||
|
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(getSource());
|
||||||
|
hashCode = 31 * hashCode + variableResolverSourceHashCode();
|
||||||
|
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.componentType);
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean variableResolverSourceEquals(VariableResolver other) {
|
||||||
|
if (this.variableResolver == null) {
|
||||||
|
return (other == null);
|
||||||
|
}
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ObjectUtils.nullSafeEquals(this.variableResolver.getSource(), other.getSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int variableResolverSourceHashCode() {
|
||||||
|
int hashCode = 0;
|
||||||
|
if (this.variableResolver != null) {
|
||||||
|
hashCode = ObjectUtils.nullSafeHashCode(this.variableResolver.getSource());
|
||||||
|
}
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts this {@link ResolvableType} to a {@link VariableResolver}.
|
||||||
|
*/
|
||||||
|
VariableResolver asVariableResolver() {
|
||||||
|
if (this == NONE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new DefaultVariableResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom serialization support for {@link #NONE}.
|
||||||
|
*/
|
||||||
|
private Object readResolve() throws ObjectStreamException {
|
||||||
|
return (this.type == null ? NONE : this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a String representation of this type in its fully resolved form
|
* Return a String representation of this type in its fully resolved form
|
||||||
* (including any generic parameters).
|
* (including any generic parameters).
|
||||||
@@ -812,90 +888,48 @@ public final class ResolvableType implements Serializable {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(obj instanceof ResolvableType)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ResolvableType other = (ResolvableType) obj;
|
|
||||||
return (ObjectUtils.nullSafeEquals(this.type, other.type) &&
|
|
||||||
ObjectUtils.nullSafeEquals(getSource(), other.getSource()) &&
|
|
||||||
variableResolverSourceEquals(other.variableResolver) &&
|
|
||||||
ObjectUtils.nullSafeEquals(this.componentType, other.componentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// Factory methods
|
||||||
public int hashCode() {
|
|
||||||
int hashCode = ObjectUtils.nullSafeHashCode(this.type);
|
|
||||||
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(getSource());
|
|
||||||
hashCode = 31 * hashCode + variableResolverSourceHashCode();
|
|
||||||
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.componentType);
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom serialization support for {@link #NONE}.
|
* Return a {@link ResolvableType} for the specified {@link Class},
|
||||||
*/
|
* using the full generic type information for assignability checks.
|
||||||
private Object readResolve() throws ObjectStreamException {
|
* For example: {@code ResolvableType.forClass(MyArrayList.class)}.
|
||||||
return (this.type == null ? NONE : this);
|
* @param sourceClass the source class ({@code null} is semantically
|
||||||
}
|
* equivalent to {@code Object.class} for typical use cases here}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapts this {@link ResolvableType} to a {@link VariableResolver}.
|
|
||||||
*/
|
|
||||||
VariableResolver asVariableResolver() {
|
|
||||||
if (this == NONE) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new DefaultVariableResolver();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean variableResolverSourceEquals(VariableResolver other) {
|
|
||||||
if (this.variableResolver == null) {
|
|
||||||
return (other == null);
|
|
||||||
}
|
|
||||||
if (other == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ObjectUtils.nullSafeEquals(this.variableResolver.getSource(), other.getSource());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int variableResolverSourceHashCode() {
|
|
||||||
int hashCode = 0;
|
|
||||||
if (this.variableResolver != null) {
|
|
||||||
hashCode = ObjectUtils.nullSafeHashCode(this.variableResolver.getSource());
|
|
||||||
}
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) {
|
|
||||||
ResolvableType[] result = new ResolvableType[types.length];
|
|
||||||
for (int i = 0; i < types.length; i++) {
|
|
||||||
result[i] = forType(types[i], owner);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a {@link ResolvableType} for the specified {@link Class}. For example
|
|
||||||
* {@code ResolvableType.forClass(MyArrayList.class)}.
|
|
||||||
* @param sourceClass the source class (must not be {@code null}
|
|
||||||
* @return a {@link ResolvableType} for the specified class
|
* @return a {@link ResolvableType} for the specified class
|
||||||
* @see #forClass(Class, Class)
|
* @see #forClass(Class, Class)
|
||||||
* @see #forClassWithGenerics(Class, Class...)
|
* @see #forClassWithGenerics(Class, Class...)
|
||||||
*/
|
*/
|
||||||
public static ResolvableType forClass(Class<?> sourceClass) {
|
public static ResolvableType forClass(Class<?> sourceClass) {
|
||||||
Assert.notNull(sourceClass, "Source class must not be null");
|
return new ResolvableType(sourceClass);
|
||||||
return forType(sourceClass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@link ResolvableType} for the specified {@link Class} with a given
|
* Return a {@link ResolvableType} for the specified {@link Class}, doing
|
||||||
* implementation. For example
|
* assignability checks against the raw class only (analogous to
|
||||||
* {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
|
* {@link Class#isAssignableFrom}, which this serves as a wrapper for.
|
||||||
|
* For example: {@code ResolvableType.forClass(MyArrayList.class)}.
|
||||||
|
* @param sourceClass the source class ({@code null} is semantically
|
||||||
|
* equivalent to {@code Object.class} for typical use cases here}
|
||||||
|
* @return a {@link ResolvableType} for the specified class
|
||||||
|
* @since 4.2
|
||||||
|
* @see #forClass(Class)
|
||||||
|
* @see #getRawClass()
|
||||||
|
*/
|
||||||
|
public static ResolvableType forRawClass(Class<?> sourceClass) {
|
||||||
|
return new ResolvableType(sourceClass) {
|
||||||
|
@Override
|
||||||
|
public boolean isAssignableFrom(Class<?> other) {
|
||||||
|
return ClassUtils.isAssignable(getRawClass(), other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a {@link ResolvableType} for the specified {@link Class}
|
||||||
|
* with a given implementation.
|
||||||
|
* For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
|
||||||
* @param sourceClass the source class (must not be {@code null}
|
* @param sourceClass the source class (must not be {@code null}
|
||||||
* @param implementationClass the implementation class
|
* @param implementationClass the implementation class
|
||||||
* @return a {@link ResolvableType} for the specified class backed by the given
|
* @return a {@link ResolvableType} for the specified class backed by the given
|
||||||
@@ -909,6 +943,47 @@ public final class ResolvableType implements Serializable {
|
|||||||
return (asType == NONE ? forType(sourceClass) : asType);
|
return (asType == NONE ? forType(sourceClass) : asType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||||
|
* @param sourceClass the source class
|
||||||
|
* @param generics the generics of the class
|
||||||
|
* @return a {@link ResolvableType} for the specific class and generics
|
||||||
|
* @see #forClassWithGenerics(Class, ResolvableType...)
|
||||||
|
*/
|
||||||
|
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, Class<?>... generics) {
|
||||||
|
Assert.notNull(sourceClass, "Source class must not be null");
|
||||||
|
Assert.notNull(generics, "Generics must not be null");
|
||||||
|
ResolvableType[] resolvableGenerics = new ResolvableType[generics.length];
|
||||||
|
for (int i = 0; i < generics.length; i++) {
|
||||||
|
resolvableGenerics[i] = forClass(generics[i]);
|
||||||
|
}
|
||||||
|
return forClassWithGenerics(sourceClass, resolvableGenerics);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
||||||
|
* @param sourceClass the source class
|
||||||
|
* @param generics the generics of the class
|
||||||
|
* @return a {@link ResolvableType} for the specific class and generics
|
||||||
|
* @see #forClassWithGenerics(Class, Class...)
|
||||||
|
*/
|
||||||
|
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, ResolvableType... generics) {
|
||||||
|
Assert.notNull(sourceClass, "Source class must not be null");
|
||||||
|
Assert.notNull(generics, "Generics must not be null");
|
||||||
|
TypeVariable<?>[] variables = sourceClass.getTypeParameters();
|
||||||
|
Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified");
|
||||||
|
|
||||||
|
Type[] arguments = new Type[generics.length];
|
||||||
|
for (int i = 0; i < generics.length; i++) {
|
||||||
|
ResolvableType generic = generics[i];
|
||||||
|
Type argument = (generic != null ? generic.getType() : null);
|
||||||
|
arguments[i] = (argument != null ? argument : variables[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterizedType syntheticType = new SyntheticParameterizedType(sourceClass, arguments);
|
||||||
|
return forType(syntheticType, new TypeVariablesVariableResolver(variables, generics));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@link ResolvableType} for the specified {@link Field}.
|
* Return a {@link ResolvableType} for the specified {@link Field}.
|
||||||
* @param field the source field
|
* @param field the source field
|
||||||
@@ -1123,50 +1198,17 @@ public final class ResolvableType implements Serializable {
|
|||||||
* @return a {@link ResolvableType} as an array of the specified component type
|
* @return a {@link ResolvableType} as an array of the specified component type
|
||||||
*/
|
*/
|
||||||
public static ResolvableType forArrayComponent(ResolvableType componentType) {
|
public static ResolvableType forArrayComponent(ResolvableType componentType) {
|
||||||
Assert.notNull(componentType, "ComponentType must not be null");
|
Assert.notNull(componentType, "componentType must not be null");
|
||||||
Class<?> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass();
|
Class<?> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass();
|
||||||
return new ResolvableType(arrayClass, null, null, componentType);
|
return new ResolvableType(arrayClass, null, null, componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) {
|
||||||
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
ResolvableType[] result = new ResolvableType[types.length];
|
||||||
* @param sourceClass the source class
|
for (int i = 0; i < types.length; i++) {
|
||||||
* @param generics the generics of the class
|
result[i] = forType(types[i], owner);
|
||||||
* @return a {@link ResolvableType} for the specific class and generics
|
|
||||||
* @see #forClassWithGenerics(Class, ResolvableType...)
|
|
||||||
*/
|
|
||||||
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, Class<?>... generics) {
|
|
||||||
Assert.notNull(sourceClass, "Source class must not be null");
|
|
||||||
Assert.notNull(generics, "Generics must not be null");
|
|
||||||
ResolvableType[] resolvableGenerics = new ResolvableType[generics.length];
|
|
||||||
for (int i = 0; i < generics.length; i++) {
|
|
||||||
resolvableGenerics[i] = forClass(generics[i]);
|
|
||||||
}
|
}
|
||||||
return forClassWithGenerics(sourceClass, resolvableGenerics);
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
|
|
||||||
* @param sourceClass the source class
|
|
||||||
* @param generics the generics of the class
|
|
||||||
* @return a {@link ResolvableType} for the specific class and generics
|
|
||||||
* @see #forClassWithGenerics(Class, Class...)
|
|
||||||
*/
|
|
||||||
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, ResolvableType... generics) {
|
|
||||||
Assert.notNull(sourceClass, "Source class must not be null");
|
|
||||||
Assert.notNull(generics, "Generics must not be null");
|
|
||||||
TypeVariable<?>[] variables = sourceClass.getTypeParameters();
|
|
||||||
Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified");
|
|
||||||
|
|
||||||
Type[] arguments = new Type[generics.length];
|
|
||||||
for (int i = 0; i < generics.length; i++) {
|
|
||||||
ResolvableType generic = generics[i];
|
|
||||||
Type argument = (generic != null ? generic.getType() : null);
|
|
||||||
arguments[i] = (argument != null ? argument : variables[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParameterizedType syntheticType = new SyntheticParameterizedType(sourceClass, arguments);
|
|
||||||
return forType(syntheticType, new TypeVariablesVariableResolver(variables, generics));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1223,15 +1265,15 @@ public final class ResolvableType implements Serializable {
|
|||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Purge empty entries on access since we don't have a clean-up thread or the like.
|
|
||||||
cache.purgeUnreferencedEntries();
|
|
||||||
|
|
||||||
// For simple Class references, build the wrapper right away -
|
// For simple Class references, build the wrapper right away -
|
||||||
// no expensive resolution necessary, so not worth caching...
|
// no expensive resolution necessary, so not worth caching...
|
||||||
if (type instanceof Class<?>) {
|
if (type instanceof Class) {
|
||||||
return new ResolvableType(type, typeProvider, variableResolver, null);
|
return new ResolvableType(type, typeProvider, variableResolver, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Purge empty entries on access since we don't have a clean-up thread or the like.
|
||||||
|
cache.purgeUnreferencedEntries();
|
||||||
|
|
||||||
// Check the cache - we may have a ResolvableType which has been resolved before...
|
// Check the cache - we may have a ResolvableType which has been resolved before...
|
||||||
ResolvableType key = new ResolvableType(type, typeProvider, variableResolver);
|
ResolvableType key = new ResolvableType(type, typeProvider, variableResolver);
|
||||||
ResolvableType resolvableType = cache.get(key);
|
ResolvableType resolvableType = cache.get(key);
|
||||||
|
|||||||
@@ -101,13 +101,36 @@ public class ResolvableTypeTests {
|
|||||||
public void forClass() throws Exception {
|
public void forClass() throws Exception {
|
||||||
ResolvableType type = ResolvableType.forClass(ExtendsList.class);
|
ResolvableType type = ResolvableType.forClass(ExtendsList.class);
|
||||||
assertThat(type.getType(), equalTo((Type) ExtendsList.class));
|
assertThat(type.getType(), equalTo((Type) ExtendsList.class));
|
||||||
|
assertThat(type.getRawClass(), equalTo(ExtendsList.class));
|
||||||
|
assertTrue(type.isAssignableFrom(ExtendsList.class));
|
||||||
|
assertFalse(type.isAssignableFrom(ArrayList.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void forClassMustNotBeNull() throws Exception {
|
public void forClassWithNull() throws Exception {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
ResolvableType type = ResolvableType.forClass(null);
|
||||||
this.thrown.expectMessage("Source class must not be null");
|
assertThat(type.getType(), equalTo((Type) Object.class));
|
||||||
ResolvableType.forClass(null);
|
assertThat(type.getRawClass(), equalTo(Object.class));
|
||||||
|
assertTrue(type.isAssignableFrom(Object.class));
|
||||||
|
assertTrue(type.isAssignableFrom(String.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void forRawClass() throws Exception {
|
||||||
|
ResolvableType type = ResolvableType.forRawClass(ExtendsList.class);
|
||||||
|
assertThat(type.getType(), equalTo((Type) ExtendsList.class));
|
||||||
|
assertThat(type.getRawClass(), equalTo(ExtendsList.class));
|
||||||
|
assertTrue(type.isAssignableFrom(ExtendsList.class));
|
||||||
|
assertFalse(type.isAssignableFrom(ArrayList.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void forRawClassWithNull() throws Exception {
|
||||||
|
ResolvableType type = ResolvableType.forRawClass(null);
|
||||||
|
assertThat(type.getType(), equalTo((Type) Object.class));
|
||||||
|
assertThat(type.getRawClass(), equalTo(Object.class));
|
||||||
|
assertTrue(type.isAssignableFrom(Object.class));
|
||||||
|
assertTrue(type.isAssignableFrom(String.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user