#486 - Fixed assignment checks of ResolvableTypes for wildcarded method return types.

ResourceProcessorInvoker suffered from Spring's ResolvableType.fromClass(…) using strong assignability checks between raw types and wildcarded right hand side types (i.e. Collection VS. Collection<?>). This has been reported [0] and fixed already but we have to switch to ResolvableType.fromRawClass(…) to get the desired assignment check behavior.

Tightened unit tests to verify the calls to the delegate handler, which had been disabled by accident and thus prevented us from detecting the issue with ResolvableType beforehand.

[0] https://jira.spring.io/browse/SPR-14648
This commit is contained in:
Oliver Gierke
2016-08-31 17:00:18 +02:00
parent e5c6485985
commit 642b673676
3 changed files with 105 additions and 25 deletions

View File

@@ -44,9 +44,9 @@ import org.springframework.web.method.support.ModelAndViewContainer;
@RequiredArgsConstructor
public class ResourceProcessorHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
static final ResolvableType RESOURCE_TYPE = ResolvableType.forClass(Resource.class);
static final ResolvableType RESOURCES_TYPE = ResolvableType.forClass(Resources.class);
private static final ResolvableType HTTP_ENTITY_TYPE = ResolvableType.forClass(HttpEntity.class);
static final ResolvableType RESOURCE_TYPE = ResolvableType.forRawClass(Resource.class);
static final ResolvableType RESOURCES_TYPE = ResolvableType.forRawClass(Resources.class);
private static final ResolvableType HTTP_ENTITY_TYPE = ResolvableType.forRawClass(HttpEntity.class);
static final Field CONTENT_FIELD = ReflectionUtils.findField(Resources.class, "content");

View File

@@ -367,9 +367,9 @@ public class ResourceProcessorInvoker {
ResolvableType superType = null;
for (Class<?> resourcesType : Arrays.<Class<?>> asList(resources.getClass(), Resources.class)) {
for (Class<?> resourcesType : Arrays.<Class<?>>asList(resources.getClass(), Resources.class)) {
superType = ResolvableType.forClass(resourcesType, getRawType(target));
superType = getSuperType(target, resourcesType);
if (superType != null) {
break;
@@ -391,6 +391,34 @@ public class ResourceProcessorInvoker {
return false;
}
/**
* Returns the {@link ResolvableType} for the given raw super class.
*
* @param source must not be {@literal null}.
* @param superType must not be {@literal null}.
* @return
*/
private static ResolvableType getSuperType(ResolvableType source, Class<?> superType) {
if (source.getRawClass().equals(superType)) {
return source;
}
ResolvableType candidate = source.getSuperType();
if (superType.isAssignableFrom(candidate.getRawClass())) {
return candidate;
}
for (ResolvableType interfaces : source.getInterfaces()) {
if (superType.isAssignableFrom(interfaces.getRawClass())) {
return interfaces;
}
}
return ResolvableType.forClass(superType);
}
}
/**