ConversionService detects generic type declaration on target class behind proxy as well

Issue: SPR-14822
(cherry picked from commit f7d740f)
This commit is contained in:
Juergen Hoeller
2016-10-21 12:24:12 +02:00
parent 6d95b999ad
commit f9fcd24315
5 changed files with 132 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public interface ConverterFactory<S, R> {
* Get the converter to convert from S to target type T, where T is also an instance of R.
* @param <T> the target type
* @param targetType the target type to convert to
* @return A converter from S to T
* @return a converter from S to T
*/
<T extends R> Converter<S, T> getConverter(Class<T> targetType);

View File

@@ -49,12 +49,12 @@ public interface ConverterRegistry {
/**
* Add a ranged converter factory to this registry.
* The convertible source/target type pair is derived from the ConverterFactory's parameterized types.
* @throws IllegalArgumentException if the parameterized types could not be resolved.
* @throws IllegalArgumentException if the parameterized types could not be resolved
*/
void addConverterFactory(ConverterFactory<?, ?> converterFactory);
void addConverterFactory(ConverterFactory<?, ?> factory);
/**
* Remove any converters from sourceType to targetType.
* Remove any converters from {@code sourceType} to {@code targetType}.
* @param sourceType the source type
* @param targetType the target type
*/

View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.core.DecoratingProxy;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionFailedException;
@@ -96,9 +97,14 @@ public class GenericConversionService implements ConfigurableConversionService {
@Override
public void addConverter(Converter<?, ?> converter) {
ResolvableType[] typeInfo = getRequiredTypeInfo(converter, Converter.class);
Assert.notNull(typeInfo, "Unable to the determine sourceType <S> and targetType " +
"<T> which your Converter<S, T> converts between; declare these generic types.");
ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
if (typeInfo == null && converter instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
"Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");
}
addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
}
@@ -115,11 +121,16 @@ public class GenericConversionService implements ConfigurableConversionService {
}
@Override
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
ResolvableType[] typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class);
Assert.notNull(typeInfo, "Unable to the determine source type <S> and target range type R which your " +
"ConverterFactory<S, R> converts between; declare these generic types.");
addConverter(new ConverterFactoryAdapter(converterFactory,
public void addConverterFactory(ConverterFactory<?, ?> factory) {
ResolvableType[] typeInfo = getRequiredTypeInfo(factory.getClass(), ConverterFactory.class);
if (typeInfo == null && factory instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) factory).getDecoratedClass(), ConverterFactory.class);
}
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
"ConverterFactory [" + factory.getClass().getName() + "]; does the class parameterize those types?");
}
addConverter(new ConverterFactoryAdapter(factory,
new ConvertiblePair(typeInfo[0].resolve(), typeInfo[1].resolve())));
}
@@ -284,8 +295,8 @@ public class GenericConversionService implements ConfigurableConversionService {
// Internal helpers
private ResolvableType[] getRequiredTypeInfo(Object converter, Class<?> genericIfc) {
ResolvableType resolvableType = ResolvableType.forClass(converter.getClass()).as(genericIfc);
private ResolvableType[] getRequiredTypeInfo(Class<?> converterClass, Class<?> genericIfc) {
ResolvableType resolvableType = ResolvableType.forClass(converterClass).as(genericIfc);
ResolvableType[] generics = resolvableType.getGenerics();
if (generics.length < 2) {
return null;