Browse Source

factored out common resolveTypeArgument(s) method to GenericTypeResolver

pull/23217/head
Juergen Hoeller 16 years ago
parent
commit
49bf85baaa
  1. 40
      org.springframework.context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java
  2. 83
      org.springframework.context/src/main/java/org/springframework/ui/format/support/GenericFormatterRegistry.java
  3. 73
      org.springframework.core/src/main/java/org/springframework/core/GenericTypeResolver.java
  4. 101
      org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

40
org.springframework.context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java

@ -16,10 +16,6 @@ @@ -16,10 +16,6 @@
package org.springframework.context.event;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.GenericTypeResolver;
@ -48,13 +44,15 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen @@ -48,13 +44,15 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
this.delegate = delegate;
}
@SuppressWarnings("unchecked")
public void onApplicationEvent(ApplicationEvent event) {
this.delegate.onApplicationEvent(event);
}
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return getGenericEventType(this.delegate.getClass()).isAssignableFrom(eventType);
Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
return (typeArg == null || typeArg.isAssignableFrom(eventType));
}
public boolean supportsSourceType(Class<?> sourceType) {
@ -65,36 +63,4 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen @@ -65,36 +63,4 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
}
@SuppressWarnings("unchecked")
private Class<? extends ApplicationEvent> getGenericEventType(Class<? extends ApplicationListener> currentClass) {
Class classToIntrospect = currentClass;
while (classToIntrospect != null) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
for (Type ifc : ifcs) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
if (ApplicationListener.class.equals(rawType)) {
Type arg = paramIfc.getActualTypeArguments()[0];
if (arg instanceof TypeVariable) {
arg = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg, this.delegate.getClass());
}
if (arg instanceof Class) {
return (Class) arg;
}
}
else if (ApplicationListener.class.isAssignableFrom((Class) rawType)) {
return getGenericEventType((Class) rawType);
}
}
else if (ApplicationListener.class.isAssignableFrom((Class) ifc)) {
return getGenericEventType((Class) ifc);
}
}
classToIntrospect = classToIntrospect.getSuperclass();
}
return ApplicationEvent.class;
}
}

83
org.springframework.context/src/main/java/org/springframework/ui/format/support/GenericFormatterRegistry.java

@ -17,9 +17,6 @@ @@ -17,9 +17,6 @@
package org.springframework.ui.format.support;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.Locale;
@ -182,18 +179,20 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC @@ -182,18 +179,20 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC
// implementing FormatterRegistry
public void addFormatterByType(Class<?> type, Formatter<?> formatter) {
Class<?> formattedObjectType = getFormattedObjectType(formatter.getClass());
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class);
if (!this.conversionService.canConvert(formattedObjectType, type)) {
throw new IllegalArgumentException("Unable to register Formatter " + formatter + " for type [" + type.getName() + "]; not able to convert from [" + formattedObjectType.getName() + "] to parse");
throw new IllegalArgumentException("Unable to register Formatter " + formatter + " for type [" +
type.getName() + "]; not able to convert from [" + formattedObjectType.getName() + "] to parse");
}
if (!this.conversionService.canConvert(type, formattedObjectType)) {
throw new IllegalArgumentException("Unable to register Formatter " + formatter + " for type [" + type.getName() + "]; not able to convert to [" + formattedObjectType.getName() + "] to format");
throw new IllegalArgumentException("Unable to register Formatter " + formatter + " for type [" +
type.getName() + "]; not able to convert to [" + formattedObjectType.getName() + "] to format");
}
this.typeFormatters.put(type, formatter);
}
public <T> void addFormatterByType(Formatter<T> formatter) {
Class formattedObjectType = getFormattedObjectType(formatter.getClass());
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class);
this.typeFormatters.put(formattedObjectType, formatter);
}
@ -202,7 +201,13 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC @@ -202,7 +201,13 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC
}
public <A extends Annotation, T> void addFormatterByAnnotation(AnnotationFormatterFactory<A, T> factory) {
this.annotationFormatters.put(getAnnotationType(factory.getClass()), factory);
Class[] typeArgs = GenericTypeResolver.resolveTypeArguments(factory.getClass(), AnnotationFormatterFactory.class);
if (typeArgs == null) {
throw new IllegalArgumentException(
"Unable to extract Annotation type A argument from AnnotationFormatterFactory [" +
factory.getClass().getName() + "]; does the factory parameterize the <A> generic type?");
}
this.annotationFormatters.put(typeArgs[0], factory);
}
@SuppressWarnings("unchecked")
@ -218,7 +223,7 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC @@ -218,7 +223,7 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC
formatter = getTypeFormatter(type.getType());
}
if (formatter != null) {
Class<?> formattedObjectType = getFormattedObjectType(formatter.getClass());
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class);
if (!type.getType().isAssignableFrom(formattedObjectType)) {
return new ConvertingFormatter(type.getType(), formattedObjectType, formatter);
}
@ -229,66 +234,6 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC @@ -229,66 +234,6 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC
// internal helpers
private Class getFormattedObjectType(Class formatterClass) {
Class classToIntrospect = formatterClass;
while (classToIntrospect != null) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
for (Type ifc : ifcs) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
if (Formatter.class.equals(rawType)) {
Type arg = paramIfc.getActualTypeArguments()[0];
if (arg instanceof TypeVariable) {
arg = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg, formatterClass);
}
if (arg instanceof Class) {
return (Class) arg;
}
}
else if (Formatter.class.isAssignableFrom((Class) rawType)) {
return getFormattedObjectType((Class) rawType);
}
}
else if (Formatter.class.isAssignableFrom((Class) ifc)) {
return getFormattedObjectType((Class) ifc);
}
}
classToIntrospect = classToIntrospect.getSuperclass();
}
return null;
}
private Class getAnnotationType(Class factoryClass) {
Class classToIntrospect = factoryClass;
while (classToIntrospect != null) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
for (Type ifc : ifcs) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
if (AnnotationFormatterFactory.class.equals(rawType)) {
Type arg = paramIfc.getActualTypeArguments()[0];
if (arg instanceof TypeVariable) {
arg = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg, factoryClass);
}
if (arg instanceof Class) {
return (Class) arg;
}
} else if (AnnotationFormatterFactory.class.isAssignableFrom((Class) rawType)) {
return getAnnotationType((Class) rawType);
}
} else if (AnnotationFormatterFactory.class.isAssignableFrom((Class) ifc)) {
return getAnnotationType((Class) ifc);
}
}
classToIntrospect = classToIntrospect.getSuperclass();
}
throw new IllegalArgumentException(
"Unable to extract Annotation type A argument from AnnotationFormatterFactory [" +
factoryClass.getName() + "]; does the factory parameterize the <A> generic type?");
}
@SuppressWarnings("unchecked")
private Formatter getAnnotationFormatter(TypeDescriptor type) {
Annotation[] annotations = type.getAnnotations();

73
org.springframework.core/src/main/java/org/springframework/core/GenericTypeResolver.java

@ -75,7 +75,7 @@ public abstract class GenericTypeResolver { @@ -75,7 +75,7 @@ public abstract class GenericTypeResolver {
* @param clazz the class to resolve type variables against
* @return the corresponding generic parameter or return type
*/
public static Class resolveParameterType(MethodParameter methodParam, Class clazz) {
public static Class<?> resolveParameterType(MethodParameter methodParam, Class clazz) {
Type genericType = getTargetType(methodParam);
Assert.notNull(clazz, "Class must not be null");
Map<TypeVariable, Type> typeVariableMap = getTypeVariableMap(clazz);
@ -92,7 +92,7 @@ public abstract class GenericTypeResolver { @@ -92,7 +92,7 @@ public abstract class GenericTypeResolver {
* @param clazz the class to resolve type variables against
* @return the corresponding generic parameter or return type
*/
public static Class resolveReturnType(Method method, Class clazz) {
public static Class<?> resolveReturnType(Method method, Class clazz) {
Assert.notNull(method, "Method must not be null");
Type genericType = method.getGenericReturnType();
Assert.notNull(clazz, "Class must not be null");
@ -102,15 +102,68 @@ public abstract class GenericTypeResolver { @@ -102,15 +102,68 @@ public abstract class GenericTypeResolver {
}
/**
* Resolve the given type variable against the given class.
* @param tv the type variable to resolve
* @param clazz the class that defines the type variable
* somewhere in its inheritance hierarchy
* @return the resolved type that the variable can get replaced with,
* or <code>null</code> if none found
* Resolve the single type argument of the given generic interface against
* the given target class which is assumed to implement the generic interface
* and possibly declare a concrete type for its type variable.
* @param clazz the target class to check against
* @param genericIfc the generic interface to resolve the type argument from
* @return the resolved type of the argument, or <code>null</code> if not resolvable
*/
public static Type resolveTypeVariable(TypeVariable tv, Class clazz) {
return getTypeVariableMap(clazz).get(tv);
public static Class<?> resolveTypeArgument(Class clazz, Class genericIfc) {
Class[] typeArgs = resolveTypeArguments(clazz, genericIfc);
if (typeArgs == null) {
return null;
}
if (typeArgs.length != 1) {
throw new IllegalArgumentException("Expected 1 type argument on generic interface [" +
genericIfc.getName() + "] but found " + typeArgs.length);
}
return typeArgs[0];
}
/**
* Resolve the type arguments of the given generic interface against the given
* target class which is assumed to implement the generic interface and possibly
* declare concrete types for its type variables.
* @param clazz the target class to check against
* @param genericIfc the generic interface to resolve the type argument from
* @return the resolved type of each argument, with the array size matching the
* number of actual type arguments, or <code>null</code> if not resolvable
*/
public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) {
return doResolveTypeArguments(clazz, clazz, genericIfc);
}
private static Class[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) {
while (classToIntrospect != null) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
for (Type ifc : ifcs) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
if (genericIfc.equals(rawType)) {
Type[] typeArgs = paramIfc.getActualTypeArguments();
Class[] result = new Class[typeArgs.length];
for (int i = 0; i < typeArgs.length; i++) {
Type arg = typeArgs[i];
if (arg instanceof TypeVariable) {
arg = getTypeVariableMap(ownerClass).get((TypeVariable) arg);
}
result[i] = (arg instanceof Class ? (Class) arg : Object.class);
}
return result;
}
else if (genericIfc.isAssignableFrom((Class) rawType)) {
return doResolveTypeArguments(ownerClass, (Class) rawType, genericIfc);
}
}
else if (genericIfc.isAssignableFrom((Class) ifc)) {
return doResolveTypeArguments(ownerClass, (Class) ifc, genericIfc);
}
}
classToIntrospect = classToIntrospect.getSuperclass();
}
return null;
}

101
org.springframework.core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java

@ -16,18 +16,11 @@ @@ -16,18 +16,11 @@
package org.springframework.core.convert.support;
import static org.springframework.core.convert.support.ConversionUtils.invokeConverter;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -39,6 +32,7 @@ import org.springframework.core.convert.converter.Converter; @@ -39,6 +32,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterInfo;
import org.springframework.core.convert.converter.ConverterRegistry;
import static org.springframework.core.convert.support.ConversionUtils.*;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -109,27 +103,28 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -109,27 +103,28 @@ public class GenericConversionService implements ConversionService, ConverterReg
return this.parent;
}
// implementing ConverterRegistry
public void addConverter(Converter converter) {
List<Class> typeInfo = getRequiredTypeInfo(converter);
public void addConverter(Converter<?, ?> converter) {
Class[] typeInfo = getRequiredTypeInfo(converter, Converter.class);
if (typeInfo == null) {
throw new IllegalArgumentException(
"Unable to the determine sourceType <S> and targetType <T> your Converter<S, T> converts between; declare these types or implement ConverterInfo");
}
Class sourceType = typeInfo.get(0);
Class targetType = typeInfo.get(1);
Class sourceType = typeInfo[0];
Class targetType = typeInfo[1];
getSourceMap(sourceType).put(targetType, new ConverterAdapter(converter));
}
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
List<Class> typeInfo = getRequiredTypeInfo(converterFactory);
Class[] typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class);
if (typeInfo == null) {
throw new IllegalArgumentException(
"Unable to the determine sourceType <S> and targetRangeType R your ConverterFactory<S, R> converts between; declare these types or implement ConverterInfo");
}
Class sourceType = typeInfo.get(0);
Class targetType = typeInfo.get(1);
Class sourceType = typeInfo[0];
Class targetType = typeInfo[1];
getSourceMap(sourceType).put(targetType, new ConverterFactoryAdapter(converterFactory));
}
@ -137,6 +132,7 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -137,6 +132,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
getSourceMap(sourceType).remove(targetType);
}
// implementing ConversionService
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
@ -176,6 +172,7 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -176,6 +172,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
return invokeConverter(converter, source, sourceType, targetType);
}
// subclassing hooks
/**
@ -224,7 +221,7 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -224,7 +221,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
/**
* Hook method to lookup the converter for a given sourceType/targetType pair.
* First queries this ConversionService's converter map.
* If no suitable Converter is found, and a {@link #setParent(GenericConversionService) parent} is set, then queries the parent.
* If no suitable Converter is found, and a {@link #setParent parent} is set, then queries the parent.
* If still no suitable Converter is found, returns a NO_OP Converter if the sourceType and targetType are assignable.
* Returns <code>null</code> if this ConversionService simply cannot convert between sourceType and targetType.
* Subclasses may override.
@ -236,68 +233,34 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -236,68 +233,34 @@ public class GenericConversionService implements ConversionService, ConverterReg
GenericConverter converter = findConverterByClassPair(sourceType.getObjectType(), targetType.getObjectType());
if (converter != null) {
return converter;
} else if (this.parent != null && this.parent.canConvert(sourceType, targetType)) {
}
else if (this.parent != null && this.parent.canConvert(sourceType, targetType)) {
return this.parentConverterAdapter;
} else {
}
else {
if (sourceType.isAssignableTo(targetType)) {
return NO_OP_CONVERTER;
} else {
}
else {
return null;
}
}
}
// internal helpers
private List<Class> getRequiredTypeInfo(Object converter) {
List<Class> typeInfo = new ArrayList<Class>(2);
private Class[] getRequiredTypeInfo(Object converter, Class ifc) {
Class[] typeInfo = new Class[2];
if (converter instanceof ConverterInfo) {
ConverterInfo info = (ConverterInfo) converter;
typeInfo.add(info.getSourceType());
typeInfo.add(info.getTargetType());
typeInfo[0] = info.getSourceType();
typeInfo[1] = info.getTargetType();
return typeInfo;
} else {
return getConverterTypeInfo(converter.getClass());
}
}
private List<Class> getConverterTypeInfo(Class converterClass) {
Class classToIntrospect = converterClass;
while (classToIntrospect != null) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
for (Type ifc : ifcs) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
if (Converter.class.equals(rawType) || ConverterFactory.class.equals(rawType)) {
List<Class> typeInfo = new ArrayList<Class>(2);
Type arg1 = paramIfc.getActualTypeArguments()[0];
if (arg1 instanceof TypeVariable) {
arg1 = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg1, converterClass);
}
if (arg1 instanceof Class) {
typeInfo.add((Class) arg1);
}
Type arg2 = paramIfc.getActualTypeArguments()[1];
if (arg2 instanceof TypeVariable) {
arg2 = GenericTypeResolver.resolveTypeVariable((TypeVariable) arg2, converterClass);
}
if (arg2 instanceof Class) {
typeInfo.add((Class) arg2);
}
if (typeInfo.size() == 2) {
return typeInfo;
}
} else if (Converter.class.isAssignableFrom((Class) rawType)) {
return getConverterTypeInfo((Class) rawType);
}
} else if (Converter.class.isAssignableFrom((Class) ifc)) {
return getConverterTypeInfo((Class) ifc);
}
}
classToIntrospect = classToIntrospect.getSuperclass();
else {
return GenericTypeResolver.resolveTypeArguments(converter.getClass(), ifc);
}
return null;
}
private GenericConverter findConverterByClassPair(Class sourceType, Class targetType) {
@ -318,7 +281,8 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -318,7 +281,8 @@ public class GenericConversionService implements ConversionService, ConverterReg
}
Map<Class, GenericConverter> objectConverters = getConvertersForSource(Object.class);
return getConverter(objectConverters, targetType);
} else {
}
else {
LinkedList<Class> classQueue = new LinkedList<Class>();
classQueue.addFirst(sourceType);
while (!classQueue.isEmpty()) {
@ -333,7 +297,8 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -333,7 +297,8 @@ public class GenericConversionService implements ConversionService, ConverterReg
if (componentType.getSuperclass() != null) {
classQueue.addFirst(Array.newInstance(componentType.getSuperclass(), 0).getClass());
}
} else {
}
else {
if (currentClass.getSuperclass() != null) {
classQueue.addFirst(currentClass.getSuperclass());
}
@ -380,7 +345,8 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -380,7 +345,8 @@ public class GenericConversionService implements ConversionService, ConverterReg
}
}
return converters.get(Object.class);
} else {
}
else {
LinkedList<Class> classQueue = new LinkedList<Class>();
classQueue.addFirst(targetType);
while (!classQueue.isEmpty()) {
@ -394,7 +360,8 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -394,7 +360,8 @@ public class GenericConversionService implements ConversionService, ConverterReg
if (componentType.getSuperclass() != null) {
classQueue.addFirst(Array.newInstance(componentType.getSuperclass(), 0).getClass());
}
} else {
}
else {
if (currentClass.getSuperclass() != null) {
classQueue.addFirst(currentClass.getSuperclass());
}
@ -408,6 +375,7 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -408,6 +375,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
}
}
private static class ConverterAdapter implements GenericConverter {
private Converter converter;
@ -422,6 +390,7 @@ public class GenericConversionService implements ConversionService, ConverterReg @@ -422,6 +390,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
}
}
private static class ConverterFactoryAdapter implements GenericConverter {
private ConverterFactory converterFactory;

Loading…
Cancel
Save