Autowiring of generic types
Includes revisions of MethodParameter and DependencyDescriptor (in particular towards a reference to the containing class). Also refines several ResolvableType method signatures. Issue: SPR-9965
This commit is contained in:
@@ -23,11 +23,11 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
@@ -56,12 +56,14 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
|
||||
protected final List<MediaType> allSupportedMediaTypes;
|
||||
|
||||
|
||||
public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters) {
|
||||
Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
|
||||
this.messageConverters = messageConverters;
|
||||
this.allSupportedMediaTypes = getAllSupportedMediaTypes(messageConverters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the media types supported by all provided message converters sorted
|
||||
* by specificity via {@link MediaType#sortBySpecificity(List)}.
|
||||
@@ -77,9 +79,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the method argument value of the expected parameter type by
|
||||
* Create the method argument value of the expected parameter type by
|
||||
* reading from the given request.
|
||||
*
|
||||
* @param <T> the expected type of the argument value to be created
|
||||
* @param webRequest the current request
|
||||
* @param methodParam the method argument
|
||||
@@ -96,9 +97,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the method argument value of the expected parameter type by reading
|
||||
* Create the method argument value of the expected parameter type by reading
|
||||
* from the given HttpInputMessage.
|
||||
*
|
||||
* @param <T> the expected type of the argument value to be created
|
||||
* @param inputMessage the HTTP input message representing the current request
|
||||
* @param methodParam the method argument
|
||||
@@ -113,43 +113,42 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
|
||||
MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {
|
||||
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
|
||||
Class<?> contextClass = methodParam.getDeclaringClass();
|
||||
Class<T> targetClass = (Class<T>) ResolvableType.forType(targetType,
|
||||
ResolvableType.forMethodParameter(methodParam)).resolve();
|
||||
Class<?> contextClass = methodParam.getContainingClass();
|
||||
Class<T> targetClass = (Class<T>) ResolvableType.forType(targetType,
|
||||
ResolvableType.forMethodParameter(methodParam)).resolve();
|
||||
|
||||
for (HttpMessageConverter<?> converter : this.messageConverters) {
|
||||
if (converter instanceof GenericHttpMessageConverter) {
|
||||
GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter;
|
||||
if (genericConverter.canRead(targetType, contextClass, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reading [" + targetType + "] as \"" +
|
||||
contentType + "\" using [" + converter + "]");
|
||||
}
|
||||
return genericConverter.read(targetType, contextClass, inputMessage);
|
||||
}
|
||||
}
|
||||
if (targetClass != null) {
|
||||
if (converter.canRead(targetClass, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reading [" + targetClass.getName() + "] as \"" +
|
||||
contentType + "\" using [" + converter + "]");
|
||||
}
|
||||
return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
|
||||
}
|
||||
for (HttpMessageConverter<?> converter : this.messageConverters) {
|
||||
if (converter instanceof GenericHttpMessageConverter) {
|
||||
GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter;
|
||||
if (genericConverter.canRead(targetType, contextClass, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reading [" + targetType + "] as \"" +
|
||||
contentType + "\" using [" + converter + "]");
|
||||
}
|
||||
return genericConverter.read(targetType, contextClass, inputMessage);
|
||||
}
|
||||
|
||||
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
|
||||
}
|
||||
if (targetClass != null) {
|
||||
if (converter.canRead(targetClass, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reading [" + targetClass.getName() + "] as \"" +
|
||||
contentType + "\" using [" + converter + "]");
|
||||
}
|
||||
return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link HttpInputMessage} from the given {@link NativeWebRequest}.
|
||||
*
|
||||
* Create a new {@link HttpInputMessage} from the given {@link NativeWebRequest}.
|
||||
* @param webRequest the web request to create an input message from
|
||||
* @return the input message
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -80,7 +80,7 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
||||
|
||||
if (this.mavResolvers != null) {
|
||||
for (ModelAndViewResolver mavResolver : this.mavResolvers) {
|
||||
Class<?> handlerType = returnType.getDeclaringClass();
|
||||
Class<?> handlerType = returnType.getContainingClass();
|
||||
Method method = returnType.getMethod();
|
||||
ExtendedModelMap model = (ExtendedModelMap) mavContainer.getModel();
|
||||
ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, request);
|
||||
@@ -95,14 +95,13 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
||||
}
|
||||
}
|
||||
|
||||
// No suitable ModelAndViewResolver..
|
||||
|
||||
// No suitable ModelAndViewResolver...
|
||||
if (this.modelAttributeProcessor.supportsReturnType(returnType)) {
|
||||
this.modelAttributeProcessor.handleReturnValue(returnValue, returnType, mavContainer, request);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unexpected return type: "
|
||||
+ returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
|
||||
throw new UnsupportedOperationException("Unexpected return type: " +
|
||||
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -22,7 +22,6 @@ import java.io.PushbackInputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.Conventions;
|
||||
@@ -81,16 +80,16 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
||||
|
||||
@Override
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return ((AnnotationUtils.findAnnotation(returnType.getDeclaringClass(), ResponseBody.class) != null)
|
||||
|| (returnType.getMethodAnnotation(ResponseBody.class) != null));
|
||||
return ((AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) ||
|
||||
(returnType.getMethodAnnotation(ResponseBody.class) != null));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws MethodArgumentNotValidException if validation fails
|
||||
* @throws HttpMessageNotReadableException if {@link RequestBody#required()}
|
||||
* is {@code true} and there is no body content or if there is no suitable
|
||||
* converter to read the content with.
|
||||
* is {@code true} and there is no body content or if there is no suitable
|
||||
* converter to read the content with.
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
|
||||
Reference in New Issue
Block a user