Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
ad2e0d45
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ad2e0d45
编写于
5月 17, 2011
作者:
A
Arjen Poutsma
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
SPR-7353 - @ResponseBody and returned HttpEntity now respect @RequestMapping.produces()
上级
57c757af
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
395 addition
and
218 deletion
+395
-218
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
...t/mvc/method/annotation/RequestMappingHandlerAdapter.java
+2
-3
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
...t/mvc/method/annotation/RequestMappingHandlerMapping.java
+57
-55
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java
...tion/support/AbstractMessageConverterMethodProcessor.java
+125
-59
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java
.../method/annotation/support/HttpEntityMethodProcessor.java
+5
-19
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java
...nnotation/support/RequestResponseBodyMethodProcessor.java
+9
-18
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/MediaTypesRequestCondition.java
...vlet/mvc/method/condition/MediaTypesRequestCondition.java
+14
-0
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java
...vlet/mvc/method/annotation/ServletHandlerMethodTests.java
+21
-8
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java
...od/annotation/support/HttpEntityMethodProcessorTests.java
+65
-24
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java
...tion/support/RequestResponseBodyMethodProcessorTests.java
+63
-23
org.springframework.web/src/main/java/org/springframework/http/MediaType.java
...web/src/main/java/org/springframework/http/MediaType.java
+11
-2
org.springframework.web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java
...framework/web/HttpRequestMethodNotSupportedException.java
+11
-1
org.springframework.web/src/test/java/org/springframework/http/MediaTypeTests.java
...rc/test/java/org/springframework/http/MediaTypeTests.java
+12
-6
未找到文件。
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
浏览文件 @
ad2e0d45
...
...
@@ -22,7 +22,6 @@ import java.util.List;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpSession
;
...
...
@@ -575,7 +574,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
/**
* MethodFilter that matches {@link InitBinder @InitBinder} methods.
*/
public
static
MethodFilter
INIT_BINDER_METHODS
=
new
MethodFilter
()
{
public
static
final
MethodFilter
INIT_BINDER_METHODS
=
new
MethodFilter
()
{
public
boolean
matches
(
Method
method
)
{
return
AnnotationUtils
.
findAnnotation
(
method
,
InitBinder
.
class
)
!=
null
;
...
...
@@ -585,7 +584,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
/**
* MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods.
*/
public
static
MethodFilter
MODEL_ATTRIBUTE_METHODS
=
new
MethodFilter
()
{
public
static
final
MethodFilter
MODEL_ATTRIBUTE_METHODS
=
new
MethodFilter
()
{
public
boolean
matches
(
Method
method
)
{
return
((
AnnotationUtils
.
findAnnotation
(
method
,
RequestMapping
.
class
)
==
null
)
&&
...
...
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java
浏览文件 @
ad2e0d45
...
...
@@ -25,6 +25,7 @@ import java.util.Iterator;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.servlet.ServletException
;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.core.annotation.AnnotationUtils
;
...
...
@@ -33,6 +34,9 @@ import org.springframework.stereotype.Controller;
import
org.springframework.util.AntPathMatcher
;
import
org.springframework.util.Assert
;
import
org.springframework.util.PathMatcher
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.HttpMediaTypeNotAcceptableException
;
import
org.springframework.web.HttpMediaTypeNotSupportedException
;
import
org.springframework.web.HttpRequestMethodNotSupportedException
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
...
...
@@ -46,9 +50,9 @@ import org.springframework.web.servlet.handler.MappedInterceptors;
import
org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory
;
/**
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingInfo}s for the registration and
*
the
lookup of {@link HandlerMethod}s.
*
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingInfo}s for the registration and
the
* lookup of {@link HandlerMethod}s.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1.0
...
...
@@ -84,10 +88,10 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
this
.
mappedInterceptors
=
MappedInterceptors
.
createFromDeclaredBeans
(
getApplicationContext
());
}
}
/**
* {@inheritDoc}
*
The handler determination in this method is made based on the presence of a type-level {@link
Controller} annotation.
* {@inheritDoc}
The handler determination in this method is made based on the presence of a type-level {@link
* Controller} annotation.
*/
@Override
protected
boolean
isHandler
(
Class
<?>
beanType
)
{
...
...
@@ -106,9 +110,8 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
}
/**
* Provides a {@link RequestMappingInfo} for the given method.
* <p>Only {@link RequestMapping @RequestMapping}-annotated methods are considered.
* Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
* Provides a {@link RequestMappingInfo} for the given method. <p>Only {@link RequestMapping @RequestMapping}-annotated
* methods are considered. Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
* attributes combined with method-level {@link RequestMapping @RequestMapping} attributes.
*
* @param method the method to create a mapping for
...
...
@@ -137,14 +140,13 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
private
static
RequestMappingInfo
createFromRequestMapping
(
RequestMapping
annotation
)
{
return
new
RequestMappingInfo
(
Arrays
.
asList
(
annotation
.
value
()),
RequestConditionFactory
.
parseMethods
(
annotation
.
method
()),
RequestConditionFactory
.
parseParams
(
annotation
.
params
()),
RequestConditionFactory
.
parseHeaders
(
annotation
.
headers
()),
RequestConditionFactory
.
parseConsumes
(
annotation
.
consumes
(),
annotation
.
headers
()),
RequestConditionFactory
.
parseProduces
(
annotation
.
produces
(),
annotation
.
headers
())
);
RequestConditionFactory
.
parseMethods
(
annotation
.
method
()),
RequestConditionFactory
.
parseParams
(
annotation
.
params
()),
RequestConditionFactory
.
parseHeaders
(
annotation
.
headers
()),
RequestConditionFactory
.
parseConsumes
(
annotation
.
consumes
(),
annotation
.
headers
()),
RequestConditionFactory
.
parseProduces
(
annotation
.
produces
(),
annotation
.
headers
()));
}
@Override
protected
Set
<
String
>
getMappingPaths
(
RequestMappingInfo
mapping
)
{
return
mapping
.
getPatterns
();
...
...
@@ -152,10 +154,13 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
/**
* Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
*
* @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
*/
@Override
protected
RequestMappingInfo
getMatchingMapping
(
RequestMappingInfo
mapping
,
String
lookupPath
,
HttpServletRequest
request
)
{
protected
RequestMappingInfo
getMatchingMapping
(
RequestMappingInfo
mapping
,
String
lookupPath
,
HttpServletRequest
request
)
{
return
mapping
.
getMatchingRequestMapping
(
lookupPath
,
request
,
pathMatcher
);
}
...
...
@@ -177,26 +182,43 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
/**
* Iterates all {@link RequestMappingInfo}s looking for mappings that match by URL but not by HTTP method.
* @exception HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
*
* @throws HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
*/
@Override
protected
HandlerMethod
handleNoMatch
(
Set
<
RequestMappingInfo
>
requestMappingInfos
,
String
lookupPath
,
HttpServletRequest
request
)
throws
HttpRequestMethodNotSupportedException
{
protected
HandlerMethod
handleNoMatch
(
Set
<
RequestMappingInfo
>
requestMappingInfos
,
String
lookupPath
,
HttpServletRequest
request
)
throws
ServletException
{
Set
<
String
>
allowedMethods
=
new
HashSet
<
String
>(
6
);
Set
<
MediaType
>
consumableMediaTypes
=
new
HashSet
<
MediaType
>();
Set
<
MediaType
>
producibleMediaTypes
=
new
HashSet
<
MediaType
>();
for
(
RequestMappingInfo
info
:
requestMappingInfos
)
{
for
(
String
pattern
:
info
.
getPatterns
())
{
if
(
pathMatcher
.
match
(
pattern
,
lookupPath
))
{
for
(
RequestMethod
method
:
info
.
getMethods
().
getMethods
())
{
allowedMethods
.
add
(
method
.
name
());
}
if
(!
info
.
getMethods
().
match
(
request
))
{
for
(
RequestMethod
method
:
info
.
getMethods
().
getMethods
())
{
allowedMethods
.
add
(
method
.
name
());
}
}
if
(!
info
.
getConsumes
().
match
(
request
))
{
consumableMediaTypes
.
addAll
(
info
.
getConsumes
().
getMediaTypes
());
}
if
(!
info
.
getProduces
().
match
(
request
))
{
producibleMediaTypes
.
addAll
(
info
.
getProduces
().
getMediaTypes
());
}
}
if
(!
allowedMethods
.
isEmpty
())
{
throw
new
HttpRequestMethodNotSupportedException
(
request
.
getMethod
(),
allowedMethods
.
toArray
(
new
String
[
allowedMethods
.
size
()]));
}
else
{
throw
new
HttpRequestMethodNotSupportedException
(
request
.
getMethod
(),
allowedMethods
);
}
else
if
(!
consumableMediaTypes
.
isEmpty
())
{
MediaType
contentType
=
null
;
if
(
StringUtils
.
hasLength
(
request
.
getContentType
()))
{
contentType
=
MediaType
.
parseMediaType
(
request
.
getContentType
());
}
throw
new
HttpMediaTypeNotSupportedException
(
contentType
,
new
ArrayList
<
MediaType
>(
consumableMediaTypes
));
}
else
if
(!
producibleMediaTypes
.
isEmpty
())
{
throw
new
HttpMediaTypeNotAcceptableException
(
new
ArrayList
<
MediaType
>(
producibleMediaTypes
));
}
else
{
return
null
;
}
}
...
...
@@ -218,13 +240,13 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
}
/**
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a
*
specific request. For example not all {@link RequestMappingInfo} patterns may apply to the current request.
*
Therefore an
HttpServletRequest is required as input.
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a
specific
*
request. For example not all {@link RequestMappingInfo} patterns may apply to the current request. Therefore an
* HttpServletRequest is required as input.
*
* <p>Furthermore, the following assumptions are made about the input RequestMappings:
*
<ul><li>Each RequestMappingInfo has been fully matched to the request <li>The RequestMappingInfo contains
*
matched patterns only <li>Patterns are
ordered with the best matching pattern at the top </ul>
* <p>Furthermore, the following assumptions are made about the input RequestMappings:
<ul><li>Each RequestMappingInfo
*
has been fully matched to the request <li>The RequestMappingInfo contains matched patterns only <li>Patterns are
* ordered with the best matching pattern at the top </ul>
*
* @see RequestMappingHandlerMapping#getMatchingMapping(RequestMappingInfo, String, HttpServletRequest)
*/
...
...
@@ -289,26 +311,6 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
}
}
private
int
compareAcceptHeaders
(
List
<
MediaType
>
accept
,
List
<
MediaType
>
otherAccept
)
{
for
(
MediaType
requestAccept
:
this
.
requestAcceptHeader
)
{
int
pos1
=
indexOfIncluded
(
requestAccept
,
accept
);
int
pos2
=
indexOfIncluded
(
requestAccept
,
otherAccept
);
if
(
pos1
!=
pos2
)
{
return
pos2
-
pos1
;
}
}
return
0
;
}
private
int
indexOfIncluded
(
MediaType
requestAccept
,
List
<
MediaType
>
accept
)
{
for
(
int
i
=
0
;
i
<
accept
.
size
();
i
++)
{
if
(
requestAccept
.
includes
(
accept
.
get
(
i
)))
{
return
i
;
}
}
return
-
1
;
}
}
}
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java
浏览文件 @
ad2e0d45
...
...
@@ -17,30 +17,38 @@
package
org.springframework.web.servlet.mvc.method.annotation.support
;
import
java.io.IOException
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.http.HttpInputMessage
;
import
org.springframework.http.HttpOutputMessage
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.converter.HttpMessageConverter
;
import
org.springframework.http.server.ServletServerHttpRequest
;
import
org.springframework.http.server.ServletServerHttpResponse
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.web.HttpMediaTypeNotAcceptableException
;
import
org.springframework.web.HttpMediaTypeNotSupportedException
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.context.request.NativeWebRequest
;
import
org.springframework.web.method.support.HandlerMethodArgumentResolver
;
import
org.springframework.web.method.support.HandlerMethodReturnValueHandler
;
/**
* A base class for resolving method argument values by reading from the body of a request with
*
{@link HttpMessageConverter}s and for handling method return values by writing to the response with
*
{@link
HttpMessageConverter}s.
*
* A base class for resolving method argument values by reading from the body of a request with
{@link
*
HttpMessageConverter}s and for handling method return values by writing to the response with {@link
* HttpMessageConverter}s.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
...
...
@@ -48,103 +56,161 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
public
abstract
class
AbstractMessageConverterMethodProcessor
implements
HandlerMethodArgumentResolver
,
HandlerMethodReturnValueHandler
{
private
static
final
MediaType
MEDIA_TYPE_APPLICATION
=
new
MediaType
(
"application"
);
protected
final
Log
logger
=
LogFactory
.
getLog
(
getClass
());
private
final
List
<
HttpMessageConverter
<?>>
messageConverters
;
private
final
List
<
MediaType
>
allSupportedMediaTypes
;
protected
AbstractMessageConverterMethodProcessor
(
List
<
HttpMessageConverter
<?>>
messageConverters
)
{
Assert
.
not
Null
(
messageConverters
,
"'messageConverters' must not be null
"
);
Assert
.
not
Empty
(
messageConverters
,
"'messageConverters' must not be empty
"
);
this
.
messageConverters
=
messageConverters
;
this
.
allSupportedMediaTypes
=
getAllSupportedMediaTypes
(
messageConverters
);
}
private
static
List
<
MediaType
>
getAllSupportedMediaTypes
(
List
<
HttpMessageConverter
<?>>
messageConverters
)
{
Set
<
MediaType
>
allSupportedMediaTypes
=
new
HashSet
<
MediaType
>();
for
(
HttpMessageConverter
<?>
messageConverter
:
messageConverters
)
{
allSupportedMediaTypes
.
addAll
(
messageConverter
.
getSupportedMediaTypes
());
}
List
<
MediaType
>
result
=
new
ArrayList
<
MediaType
>(
allSupportedMediaTypes
);
MediaType
.
sortBySpecificity
(
result
);
return
Collections
.
unmodifiableList
(
result
);
}
@SuppressWarnings
(
"unchecked"
)
protected
<
T
>
Object
readWithMessageConverters
(
NativeWebRequest
webRequest
,
MethodParameter
methodParam
,
Class
<
T
>
paramType
)
Class
<
T
>
paramType
)
throws
IOException
,
HttpMediaTypeNotSupportedException
{
HttpInputMessage
inputMessage
=
createInputMessage
(
webRequest
);
MediaType
contentType
=
inputMessage
.
getHeaders
().
getContentType
();
if
(
contentType
==
null
)
{
StringBuilder
builder
=
new
StringBuilder
(
ClassUtils
.
getShortName
(
methodParam
.
getParameterType
()));
String
paramName
=
methodParam
.
getParameterName
();
if
(
paramName
!=
null
)
{
builder
.
append
(
' '
);
builder
.
append
(
paramName
);
}
throw
new
HttpMediaTypeNotSupportedException
(
"Cannot read parameter ("
+
builder
.
toString
()
+
") using HttpMessageConverters: no Content-Type found in HTTP request"
);
contentType
=
MediaType
.
APPLICATION_OCTET_STREAM
;
}
List
<
MediaType
>
allSupportedMediaTypes
=
new
ArrayList
<
MediaType
>();
if
(
this
.
messageConverters
!=
null
)
{
for
(
HttpMessageConverter
<?>
messageConverter
:
this
.
messageConverters
)
{
allSupportedMediaTypes
.
addAll
(
messageConverter
.
getSupportedMediaTypes
());
if
(
messageConverter
.
canRead
(
paramType
,
contentType
))
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Reading ["
+
paramType
.
getName
()
+
"] as \""
+
contentType
+
"\" using ["
+
messageConverter
+
"]"
);
}
return
((
HttpMessageConverter
<
T
>)
messageConverter
).
read
(
paramType
,
inputMessage
);
for
(
HttpMessageConverter
<?>
messageConverter
:
this
.
messageConverters
)
{
if
(
messageConverter
.
canRead
(
paramType
,
contentType
))
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Reading ["
+
paramType
.
getName
()
+
"] as \""
+
contentType
+
"\" using ["
+
messageConverter
+
"]"
);
}
return
((
HttpMessageConverter
<
T
>)
messageConverter
).
read
(
paramType
,
inputMessage
);
}
}
throw
new
HttpMediaTypeNotSupportedException
(
contentType
,
allSupportedMediaTypes
);
}
protected
abstract
HttpInputMessage
createInputMessage
(
NativeWebRequest
webRequest
);
protected
void
writeWithMessageConverters
(
NativeWebRequest
webRequest
,
Object
returnValue
)
throws
IOException
,
HttpMediaTypeNotAcceptableException
{
writeWithMessageConverters
(
returnValue
,
createInputMessage
(
webRequest
),
createOutputMessage
(
webRequest
));
/**
* Creates a new {@link HttpInputMessage} from the given {@link NativeWebRequest}.
*
* @param webRequest the web request to create an input message from
* @return the input message
*/
protected
HttpInputMessage
createInputMessage
(
NativeWebRequest
webRequest
)
{
HttpServletRequest
servletRequest
=
webRequest
.
getNativeRequest
(
HttpServletRequest
.
class
);
return
new
ServletServerHttpRequest
(
servletRequest
);
}
protected
abstract
HttpOutputMessage
createOutputMessage
(
NativeWebRequest
webRequest
);
/**
* Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
*
* @param webRequest the web request to create an output message from
* @return the output message
*/
protected
HttpOutputMessage
createOutputMessage
(
NativeWebRequest
webRequest
)
{
HttpServletResponse
servletResponse
=
webRequest
.
getNativeResponse
(
HttpServletResponse
.
class
);
return
new
ServletServerHttpResponse
(
servletResponse
);
}
@SuppressWarnings
(
"unchecked"
)
protected
<
T
>
void
writeWithMessageConverters
(
T
returnValue
,
HttpInputMessage
inputMessage
,
protected
<
T
>
void
writeWithMessageConverters
(
T
returnValue
,
MethodParameter
returnType
,
HttpInputMessage
inputMessage
,
HttpOutputMessage
outputMessage
)
throws
IOException
,
HttpMediaTypeNotAcceptableException
{
List
<
MediaType
>
acceptedMediaTypes
=
getAcceptedMediaTypes
(
inputMessage
);
List
<
MediaType
>
allSupportedMediaTypes
=
new
ArrayList
<
MediaType
>();
if
(
this
.
messageConverters
!=
null
)
{
for
(
MediaType
acceptedMediaType
:
acceptedMediaTypes
)
{
for
(
HttpMessageConverter
<?>
messageConverter
:
this
.
messageConverters
)
{
if
(!
messageConverter
.
canWrite
(
returnValue
.
getClass
(),
acceptedMediaType
))
{
continue
;
}
((
HttpMessageConverter
<
T
>)
messageConverter
).
write
(
returnValue
,
acceptedMediaType
,
outputMessage
);
Set
<
MediaType
>
producibleMediaTypes
=
getProducibleMediaTypes
(
returnType
.
getMethod
(),
returnValue
.
getClass
());
Set
<
MediaType
>
acceptableMediaTypes
=
getAcceptableMediaTypes
(
inputMessage
);
List
<
MediaType
>
mediaTypes
=
new
ArrayList
<
MediaType
>();
for
(
MediaType
acceptableMediaType
:
acceptableMediaTypes
)
{
for
(
MediaType
producibleMediaType
:
producibleMediaTypes
)
{
if
(
acceptableMediaType
.
isCompatibleWith
(
producibleMediaType
))
{
mediaTypes
.
add
(
getMostSpecificMediaType
(
acceptableMediaType
,
producibleMediaType
));
}
}
}
if
(
mediaTypes
.
isEmpty
())
{
throw
new
HttpMediaTypeNotAcceptableException
(
allSupportedMediaTypes
);
}
MediaType
.
sortBySpecificity
(
mediaTypes
);
MediaType
selectedMediaType
=
null
;
for
(
MediaType
mediaType
:
mediaTypes
)
{
if
(
mediaType
.
isConcrete
())
{
selectedMediaType
=
mediaType
;
break
;
}
else
if
(
mediaType
.
equals
(
MediaType
.
ALL
)
||
mediaType
.
equals
(
MEDIA_TYPE_APPLICATION
))
{
selectedMediaType
=
MediaType
.
APPLICATION_OCTET_STREAM
;
}
}
if
(
selectedMediaType
!=
null
)
{
for
(
HttpMessageConverter
<?>
messageConverter
:
messageConverters
)
{
if
(
messageConverter
.
canWrite
(
returnValue
.
getClass
(),
selectedMediaType
))
{
((
HttpMessageConverter
<
T
>)
messageConverter
).
write
(
returnValue
,
selectedMediaType
,
outputMessage
);
if
(
logger
.
isDebugEnabled
())
{
MediaType
contentType
=
outputMessage
.
getHeaders
().
getContentType
();
if
(
contentType
==
null
)
{
contentType
=
acceptedMediaType
;
}
logger
.
debug
(
"Written ["
+
returnValue
+
"] as \""
+
contentType
+
"\" using ["
+
logger
.
debug
(
"Written ["
+
returnValue
+
"] as \""
+
selectedMediaType
+
"\" using ["
+
messageConverter
+
"]"
);
}
return
;
}
}
}
else
{
throw
new
HttpMediaTypeNotAcceptableException
(
allSupportedMediaTypes
);
}
}
private
Set
<
MediaType
>
getProducibleMediaTypes
(
Method
handlerMethod
,
Class
<?>
returnValueClass
)
{
RequestMapping
requestMappingAnn
=
handlerMethod
.
getAnnotation
(
RequestMapping
.
class
);
if
(
requestMappingAnn
==
null
)
{
requestMappingAnn
=
handlerMethod
.
getClass
().
getAnnotation
(
RequestMapping
.
class
);
}
Set
<
MediaType
>
result
=
new
HashSet
<
MediaType
>();
if
(
requestMappingAnn
!=
null
)
{
for
(
String
produce
:
requestMappingAnn
.
produces
())
{
result
.
add
(
MediaType
.
parseMediaType
(
produce
));
}
}
else
{
for
(
HttpMessageConverter
<?>
messageConverter
:
messageConverters
)
{
allSupportedMediaTypes
.
addAll
(
messageConverter
.
getSupportedMediaTypes
());
if
(
messageConverter
.
canWrite
(
returnValueClass
,
null
))
{
result
.
addAll
(
messageConverter
.
getSupportedMediaTypes
());
}
}
}
throw
new
HttpMediaTypeNotAcceptableException
(
allSupportedMediaTypes
);
if
(
result
.
isEmpty
())
{
result
.
add
(
MediaType
.
ALL
);
}
return
result
;
}
private
List
<
MediaType
>
getAccepted
MediaTypes
(
HttpInputMessage
inputMessage
)
{
List
<
MediaType
>
acceptedMediaTypes
=
inputMessage
.
getHeaders
().
getAccept
(
);
if
(
acceptedMediaTypes
.
isEmpty
())
{
acceptedMediaTypes
=
Collections
.
singletonList
(
MediaType
.
ALL
);
private
Set
<
MediaType
>
getAcceptable
MediaTypes
(
HttpInputMessage
inputMessage
)
{
Set
<
MediaType
>
result
=
new
HashSet
<
MediaType
>(
inputMessage
.
getHeaders
().
getAccept
()
);
if
(
result
.
isEmpty
())
{
result
.
add
(
MediaType
.
ALL
);
}
return
result
;
}
MediaType
.
sortByQualityValue
(
acceptedMediaTypes
);
return
acceptedMediaTypes
;
private
MediaType
getMostSpecificMediaType
(
MediaType
type1
,
MediaType
type2
)
{
return
MediaType
.
SPECIFICITY_COMPARATOR
.
compare
(
type1
,
type2
)
<
0
?
type1
:
type2
;
}
}
\ No newline at end of file
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java
浏览文件 @
ad2e0d45
...
...
@@ -23,9 +23,6 @@ import java.lang.reflect.ParameterizedType;
import
java.lang.reflect.Type
;
import
java.util.List
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
...
...
@@ -34,8 +31,6 @@ import org.springframework.http.HttpOutputMessage;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.converter.HttpMessageConverter
;
import
org.springframework.http.server.ServerHttpResponse
;
import
org.springframework.http.server.ServletServerHttpRequest
;
import
org.springframework.http.server.ServletServerHttpResponse
;
import
org.springframework.util.Assert
;
import
org.springframework.web.HttpMediaTypeNotSupportedException
;
import
org.springframework.web.bind.support.WebDataBinderFactory
;
...
...
@@ -71,8 +66,10 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
NativeWebRequest
webRequest
,
WebDataBinderFactory
binderFactory
)
throws
IOException
,
HttpMediaTypeNotSupportedException
{
HttpInputMessage
inputMessage
=
createInputMessage
(
webRequest
);
Class
<?>
paramType
=
getHttpEntityType
(
parameter
);
Object
body
=
readWithMessageConverters
(
webRequest
,
parameter
,
paramType
);
return
new
HttpEntity
<
Object
>(
body
,
inputMessage
.
getHeaders
());
}
...
...
@@ -88,7 +85,7 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
else
if
(
typeArgument
instanceof
GenericArrayType
)
{
Type
componentType
=
((
GenericArrayType
)
typeArgument
).
getGenericComponentType
();
if
(
componentType
instanceof
Class
)
{
// Surely, there should be a nicer way to d
o this
// Surely, there should be a nicer way to d
etermine the array type
Object
array
=
Array
.
newInstance
((
Class
<?>)
componentType
,
0
);
return
array
.
getClass
();
}
...
...
@@ -97,17 +94,12 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
throw
new
IllegalArgumentException
(
"HttpEntity parameter ("
+
methodParam
.
getParameterName
()
+
") is not parameterized"
);
}
@Override
protected
HttpInputMessage
createInputMessage
(
NativeWebRequest
webRequest
)
{
HttpServletRequest
servletRequest
=
webRequest
.
getNativeRequest
(
HttpServletRequest
.
class
);
return
new
ServletServerHttpRequest
(
servletRequest
);
}
public
void
handleReturnValue
(
Object
returnValue
,
MethodParameter
returnType
,
ModelAndViewContainer
mavContainer
,
NativeWebRequest
webRequest
)
throws
Exception
{
mavContainer
.
setResolveView
(
false
);
if
(
returnValue
==
null
)
{
...
...
@@ -129,7 +121,7 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
Object
body
=
responseEntity
.
getBody
();
if
(
body
!=
null
)
{
writeWithMessageConverters
(
body
,
createInputMessage
(
webRequest
),
outputMessage
);
writeWithMessageConverters
(
body
,
returnType
,
createInputMessage
(
webRequest
),
outputMessage
);
}
else
{
// flush headers to the HttpServletResponse
...
...
@@ -137,10 +129,4 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
}
}
@Override
protected
HttpOutputMessage
createOutputMessage
(
NativeWebRequest
webRequest
)
{
HttpServletResponse
servletResponse
=
(
HttpServletResponse
)
webRequest
.
getNativeResponse
();
return
new
ServletServerHttpResponse
(
servletResponse
);
}
}
\ No newline at end of file
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java
浏览文件 @
ad2e0d45
...
...
@@ -18,15 +18,11 @@ package org.springframework.web.servlet.mvc.method.annotation.support;
import
java.io.IOException
;
import
java.util.List
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.http.HttpInputMessage
;
import
org.springframework.http.HttpOutputMessage
;
import
org.springframework.http.converter.HttpMessageConverter
;
import
org.springframework.http.server.ServletServerHttpRequest
;
import
org.springframework.http.server.ServletServerHttpResponse
;
import
org.springframework.web.HttpMediaTypeNotAcceptableException
;
import
org.springframework.web.HttpMediaTypeNotSupportedException
;
...
...
@@ -37,8 +33,8 @@ import org.springframework.web.context.request.NativeWebRequest;
import
org.springframework.web.method.support.ModelAndViewContainer
;
/**
* Resolves method arguments annotated with @{@link RequestBody}.
*
Handles return values from methods annotated with @
{@link ResponseBody}.
* Resolves method arguments annotated with @{@link RequestBody}.
Handles return values from methods annotated with
* {@link ResponseBody}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
...
...
@@ -60,25 +56,20 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
public
Object
resolveArgument
(
MethodParameter
parameter
,
ModelAndViewContainer
mavContainer
,
NativeWebRequest
webRequest
,
NativeWebRequest
webRequest
,
WebDataBinderFactory
binderFactory
)
throws
IOException
,
HttpMediaTypeNotSupportedException
{
return
readWithMessageConverters
(
webRequest
,
parameter
,
parameter
.
getParameterType
());
}
@Override
protected
HttpInputMessage
createInputMessage
(
NativeWebRequest
webRequest
)
{
HttpServletRequest
servletRequest
=
webRequest
.
getNativeRequest
(
HttpServletRequest
.
class
);
return
new
ServletServerHttpRequest
(
servletRequest
);
}
public
void
handleReturnValue
(
Object
returnValue
,
MethodParameter
returnType
,
ModelAndViewContainer
mavContainer
,
public
void
handleReturnValue
(
Object
returnValue
,
MethodParameter
returnType
,
ModelAndViewContainer
mavContainer
,
NativeWebRequest
webRequest
)
throws
IOException
,
HttpMediaTypeNotAcceptableException
{
mavContainer
.
setResolveView
(
false
);
if
(
returnValue
!=
null
)
{
writeWithMessageConverters
(
webRequest
,
returnValue
);
writeWithMessageConverters
(
returnValue
,
returnType
,
createInputMessage
(
webRequest
),
createOutputMessage
(
webRequest
));
}
}
...
...
@@ -87,5 +78,5 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
HttpServletResponse
servletResponse
=
(
HttpServletResponse
)
webRequest
.
getNativeResponse
();
return
new
ServletServerHttpResponse
(
servletResponse
);
}
}
\ No newline at end of file
org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/MediaTypesRequestCondition.java
浏览文件 @
ad2e0d45
...
...
@@ -19,7 +19,9 @@ package org.springframework.web.servlet.mvc.method.condition;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Set
;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.http.MediaType
;
...
...
@@ -54,6 +56,18 @@ class MediaTypesRequestCondition<T extends MediaTypesRequestCondition.MediaTypeR
return
sortedConditions
;
}
/**
* Returns all {@link MediaType}s contained in this condition.
*/
public
Set
<
MediaType
>
getMediaTypes
()
{
Set
<
MediaType
>
result
=
new
LinkedHashSet
<
MediaType
>();
for
(
MediaTypeRequestCondition
condition
:
getConditions
())
{
result
.
add
(
condition
.
getMediaType
());
}
return
result
;
}
/**
* @author Arjen Poutsma
*/
...
...
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java
浏览文件 @
ad2e0d45
...
...
@@ -806,13 +806,10 @@ public class ServletHandlerMethodTests {
@Test
public
void
responseBodyNoAcceptableMediaType
()
throws
ServletException
,
IOException
{
initDispatcherServlet
(
RequestResponseBodyController
.
class
,
new
BeanDefinitionRegistrar
()
{
initDispatcherServlet
(
RequestResponseBody
Produces
Controller
.
class
,
new
BeanDefinitionRegistrar
()
{
public
void
register
(
GenericWebApplicationContext
wac
)
{
RootBeanDefinition
converterDef
=
new
RootBeanDefinition
(
StringHttpMessageConverter
.
class
);
converterDef
.
getPropertyValues
().
add
(
"supportedMediaTypes"
,
new
MediaType
(
"text"
,
"plain"
));
RootBeanDefinition
adapterDef
=
new
RootBeanDefinition
(
RequestMappingHandlerAdapter
.
class
);
StringHttpMessageConverter
converter
=
new
StringHttpMessageConverter
();
converter
.
setSupportedMediaTypes
(
Collections
.
singletonList
(
new
MediaType
(
"text"
,
"plain"
)));
adapterDef
.
getPropertyValues
().
add
(
"messageConverters"
,
converter
);
wac
.
registerBeanDefinition
(
"handlerAdapter"
,
adapterDef
);
}
...
...
@@ -923,7 +920,7 @@ public class ServletHandlerMethodTests {
* See SPR-6877
*/
@Test
public
void
overlappingMess
s
ageConvertersRequestBody
()
throws
ServletException
,
IOException
{
public
void
overlappingMessageConvertersRequestBody
()
throws
ServletException
,
IOException
{
initDispatcherServlet
(
RequestResponseBodyController
.
class
,
new
BeanDefinitionRegistrar
()
{
public
void
register
(
GenericWebApplicationContext
wac
)
{
RootBeanDefinition
adapterDef
=
new
RootBeanDefinition
(
RequestMappingHandlerAdapter
.
class
);
...
...
@@ -942,7 +939,7 @@ public class ServletHandlerMethodTests {
request
.
addHeader
(
"Accept"
,
"application/json, text/javascript, */*"
);
MockHttpServletResponse
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
assertEquals
(
"Invalid
response status cod
e"
,
"application/json"
,
response
.
getHeader
(
"Content-Type"
));
assertEquals
(
"Invalid
content-typ
e"
,
"application/json"
,
response
.
getHeader
(
"Content-Type"
));
}
@Test
...
...
@@ -1006,7 +1003,7 @@ public class ServletHandlerMethodTests {
request
.
setContentType
(
"application/xml"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
assertEquals
(
4
04
,
response
.
getStatus
());
assertEquals
(
4
15
,
response
.
getStatus
());
}
@Test
...
...
@@ -1053,6 +1050,12 @@ public class ServletHandlerMethodTests {
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
assertEquals
(
"xml"
,
response
.
getContentAsString
());
request
=
new
MockHttpServletRequest
(
"GET"
,
"/something"
);
request
.
addHeader
(
"Accept"
,
"application/msword"
);
response
=
new
MockHttpServletResponse
();
servlet
.
service
(
request
,
response
);
assertEquals
(
406
,
response
.
getStatus
());
}
@Test
...
...
@@ -2159,6 +2162,16 @@ public class ServletHandlerMethodTests {
}
}
@Controller
public
static
class
RequestResponseBodyProducesController
{
@RequestMapping
(
value
=
"/something"
,
method
=
RequestMethod
.
PUT
,
produces
=
"text/plain"
)
@ResponseBody
public
String
handle
(
@RequestBody
String
body
)
throws
IOException
{
return
body
;
}
}
@Controller
public
static
class
ResponseBodyVoidController
{
...
...
@@ -2608,7 +2621,7 @@ public class ServletHandlerMethodTests {
}
private
interface
BeanDefinitionRegistrar
{
public
void
register
(
GenericWebApplicationContext
context
);
void
register
(
GenericWebApplicationContext
context
);
}
@SuppressWarnings
(
"serial"
)
...
...
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java
浏览文件 @
ad2e0d45
...
...
@@ -16,26 +16,14 @@
package
org.springframework.web.servlet.mvc.method.annotation.support
;
import
static
org
.
easymock
.
EasyMock
.
capture
;
import
static
org
.
easymock
.
EasyMock
.
createMock
;
import
static
org
.
easymock
.
EasyMock
.
eq
;
import
static
org
.
easymock
.
EasyMock
.
expect
;
import
static
org
.
easymock
.
EasyMock
.
isA
;
import
static
org
.
easymock
.
EasyMock
.
replay
;
import
static
org
.
easymock
.
EasyMock
.
verify
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
junit
.
Assert
.
fail
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.
List
;
import
java.util.
Collections
;
import
org.easymock.Capture
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
...
...
@@ -49,9 +37,13 @@ import org.springframework.mock.web.MockHttpServletRequest;
import
org.springframework.mock.web.MockHttpServletResponse
;
import
org.springframework.web.HttpMediaTypeNotAcceptableException
;
import
org.springframework.web.HttpMediaTypeNotSupportedException
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.context.request.ServletWebRequest
;
import
org.springframework.web.method.support.ModelAndViewContainer
;
import
static
org
.
easymock
.
EasyMock
.*;
import
static
org
.
junit
.
Assert
.*;
/**
* Test fixture with {@link HttpEntityMethodProcessor} and mock {@link HttpMessageConverter}.
*
...
...
@@ -70,9 +62,10 @@ public class HttpEntityMethodProcessorTests {
private
MethodParameter
returnTypeResponseEntity
;
private
MethodParameter
returnTypeHttpEntity
;
private
MethodParameter
returnTypeInt
;
private
MethodParameter
returnTypeResponseEntityProduces
;
private
ModelAndViewContainer
mavContainer
;
private
ServletWebRequest
webRequest
;
private
MockHttpServletResponse
servletResponse
;
...
...
@@ -83,10 +76,12 @@ public class HttpEntityMethodProcessorTests {
@Before
public
void
setUp
()
throws
Exception
{
messageConverter
=
createMock
(
HttpMessageConverter
.
class
);
List
<
HttpMessageConverter
<?>>
messageConverters
=
new
ArrayList
<
HttpMessageConverter
<?>>();
messageConverters
.
add
(
messageConverter
);
processor
=
new
HttpEntityMethodProcessor
(
messageConverters
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Collections
.
singletonList
(
MediaType
.
TEXT_PLAIN
));
replay
(
messageConverter
);
processor
=
new
HttpEntityMethodProcessor
(
Collections
.<
HttpMessageConverter
<?>>
singletonList
(
messageConverter
));
reset
(
messageConverter
);
Method
handle1
=
getClass
().
getMethod
(
"handle1"
,
HttpEntity
.
class
,
ResponseEntity
.
class
,
Integer
.
TYPE
);
paramHttpEntity
=
new
MethodParameter
(
handle1
,
0
);
...
...
@@ -95,8 +90,11 @@ public class HttpEntityMethodProcessorTests {
returnTypeResponseEntity
=
new
MethodParameter
(
handle1
,
-
1
);
returnTypeHttpEntity
=
new
MethodParameter
(
getClass
().
getMethod
(
"handle2"
,
HttpEntity
.
class
),
-
1
);
returnTypeInt
=
new
MethodParameter
(
getClass
().
getMethod
(
"handle3"
),
-
1
);
returnTypeResponseEntityProduces
=
new
MethodParameter
(
getClass
().
getMethod
(
"handle4"
),
-
1
);
mavContainer
=
new
ModelAndViewContainer
();
servletRequest
=
new
MockHttpServletRequest
();
...
...
@@ -124,7 +122,6 @@ public class HttpEntityMethodProcessorTests {
servletRequest
.
addHeader
(
"Content-Type"
,
contentType
.
toString
());
String
body
=
"Foo"
;
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
contentType
));
expect
(
messageConverter
.
canRead
(
String
.
class
,
contentType
)).
andReturn
(
true
);
expect
(
messageConverter
.
read
(
eq
(
String
.
class
),
isA
(
HttpInputMessage
.
class
))).
andReturn
(
body
);
replay
(
messageConverter
);
...
...
@@ -165,6 +162,8 @@ public class HttpEntityMethodProcessorTests {
MediaType
accepted
=
MediaType
.
TEXT_PLAIN
;
servletRequest
.
addHeader
(
"Accept"
,
accepted
.
toString
());
expect
(
messageConverter
.
canWrite
(
String
.
class
,
null
)).
andReturn
(
true
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Collections
.
singletonList
(
MediaType
.
TEXT_PLAIN
));
expect
(
messageConverter
.
canWrite
(
String
.
class
,
accepted
)).
andReturn
(
true
);
messageConverter
.
write
(
eq
(
body
),
eq
(
accepted
),
isA
(
HttpOutputMessage
.
class
));
replay
(
messageConverter
);
...
...
@@ -175,22 +174,56 @@ public class HttpEntityMethodProcessorTests {
verify
(
messageConverter
);
}
@Test
public
void
handleReturnValueProduces
()
throws
Exception
{
String
body
=
"Foo"
;
ResponseEntity
<
String
>
returnValue
=
new
ResponseEntity
<
String
>(
body
,
HttpStatus
.
OK
);
servletRequest
.
addHeader
(
"Accept"
,
"text/*"
);
expect
(
messageConverter
.
canWrite
(
String
.
class
,
MediaType
.
TEXT_HTML
)).
andReturn
(
true
);
messageConverter
.
write
(
eq
(
body
),
eq
(
MediaType
.
TEXT_HTML
),
isA
(
HttpOutputMessage
.
class
));
replay
(
messageConverter
);
processor
.
handleReturnValue
(
returnValue
,
returnTypeResponseEntityProduces
,
mavContainer
,
webRequest
);
assertFalse
(
mavContainer
.
isResolveView
());
verify
(
messageConverter
);
}
@Test
(
expected
=
HttpMediaTypeNotAcceptableException
.
class
)
public
void
handleReturnValueNotAcceptable
()
throws
Exception
{
String
body
=
"Foo"
;
ResponseEntity
<
String
>
returnValue
=
new
ResponseEntity
<
String
>(
body
,
HttpStatus
.
OK
);
MediaType
accepted
=
MediaType
.
TEXT_PLAIN
;
MediaType
accepted
=
MediaType
.
APPLICATION_ATOM_XML
;
servletRequest
.
addHeader
(
"Accept"
,
accepted
.
toString
());
expect
(
messageConverter
.
canWrite
(
String
.
class
,
null
)).
andReturn
(
true
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
MediaType
.
TEXT_PLAIN
));
expect
(
messageConverter
.
canWrite
(
String
.
class
,
accepted
)).
andReturn
(
false
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
MediaType
.
APPLICATION_OCTET_STREAM
));
replay
(
messageConverter
);
processor
.
handleReturnValue
(
returnValue
,
returnTypeResponseEntity
,
mavContainer
,
webRequest
);
fail
(
"Expected exception"
);
}
@Test
(
expected
=
HttpMediaTypeNotAcceptableException
.
class
)
public
void
handleReturnValueNotAcceptableProduces
()
throws
Exception
{
String
body
=
"Foo"
;
ResponseEntity
<
String
>
returnValue
=
new
ResponseEntity
<
String
>(
body
,
HttpStatus
.
OK
);
MediaType
accepted
=
MediaType
.
TEXT_PLAIN
;
servletRequest
.
addHeader
(
"Accept"
,
accepted
.
toString
());
expect
(
messageConverter
.
canWrite
(
String
.
class
,
accepted
)).
andReturn
(
false
);
replay
(
messageConverter
);
processor
.
handleReturnValue
(
returnValue
,
returnTypeResponseEntityProduces
,
mavContainer
,
webRequest
);
fail
(
"Expected exception"
);
}
@Test
public
void
responseHeaderNoBody
()
throws
Exception
{
...
...
@@ -211,8 +244,10 @@ public class HttpEntityMethodProcessorTests {
ResponseEntity
<
String
>
returnValue
=
new
ResponseEntity
<
String
>(
"body"
,
responseHeaders
,
HttpStatus
.
ACCEPTED
);
Capture
<
HttpOutputMessage
>
outputMessage
=
new
Capture
<
HttpOutputMessage
>();
expect
(
messageConverter
.
canWrite
(
String
.
class
,
MediaType
.
ALL
)).
andReturn
(
true
);
messageConverter
.
write
(
eq
(
"body"
),
eq
(
MediaType
.
ALL
),
capture
(
outputMessage
));
expect
(
messageConverter
.
canWrite
(
String
.
class
,
null
)).
andReturn
(
true
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
MediaType
.
TEXT_PLAIN
));
expect
(
messageConverter
.
canWrite
(
String
.
class
,
MediaType
.
TEXT_PLAIN
)).
andReturn
(
true
);
messageConverter
.
write
(
eq
(
"body"
),
eq
(
MediaType
.
TEXT_PLAIN
),
capture
(
outputMessage
));
replay
(
messageConverter
);
processor
.
handleReturnValue
(
returnValue
,
returnTypeResponseEntity
,
mavContainer
,
webRequest
);
...
...
@@ -234,4 +269,10 @@ public class HttpEntityMethodProcessorTests {
return
42
;
}
@RequestMapping
(
produces
=
{
"text/html"
,
"application/xhtml+xml"
})
public
ResponseEntity
<
String
>
handle4
()
{
return
null
;
}
}
\ No newline at end of file
org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java
浏览文件 @
ad2e0d45
...
...
@@ -16,24 +16,13 @@
package
org.springframework.web.servlet.mvc.method.annotation.support
;
import
static
org
.
easymock
.
EasyMock
.
createMock
;
import
static
org
.
easymock
.
EasyMock
.
eq
;
import
static
org
.
easymock
.
EasyMock
.
expect
;
import
static
org
.
easymock
.
EasyMock
.
isA
;
import
static
org
.
easymock
.
EasyMock
.
replay
;
import
static
org
.
easymock
.
EasyMock
.
verify
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
junit
.
Assert
.
fail
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.
List
;
import
java.util.
Collections
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.core.MethodParameter
;
import
org.springframework.http.HttpInputMessage
;
import
org.springframework.http.HttpOutputMessage
;
...
...
@@ -44,11 +33,15 @@ import org.springframework.mock.web.MockHttpServletResponse;
import
org.springframework.web.HttpMediaTypeNotAcceptableException
;
import
org.springframework.web.HttpMediaTypeNotSupportedException
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.context.request.NativeWebRequest
;
import
org.springframework.web.context.request.ServletWebRequest
;
import
org.springframework.web.method.support.ModelAndViewContainer
;
import
static
org
.
easymock
.
EasyMock
.*;
import
static
org
.
junit
.
Assert
.*;
/**
* Test fixture with {@link RequestResponseBodyMethodProcessor} and mock {@link HttpMessageConverter}.
*
...
...
@@ -66,31 +59,40 @@ public class RequestResponseBodyMethodProcessorTests {
private
MethodParameter
returnTypeString
;
private
MethodParameter
returnTypeInt
;
private
MethodParameter
returnTypeStringProduces
;
private
ModelAndViewContainer
mavContainer
;
private
NativeWebRequest
webRequest
;
private
MockHttpServletRequest
servletRequest
;
private
MockHttpServletResponse
servletResponse
;
@SuppressWarnings
(
"unchecked"
)
@Before
public
void
setUp
()
throws
Exception
{
messageConverter
=
createMock
(
HttpMessageConverter
.
class
);
List
<
HttpMessageConverter
<?>>
messageConverters
=
new
ArrayList
<
HttpMessageConverter
<?>>();
messageConverters
.
add
(
messageConverter
);
processor
=
new
RequestResponseBodyMethodProcessor
(
messageConverters
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Collections
.
singletonList
(
MediaType
.
TEXT_PLAIN
));
replay
(
messageConverter
);
processor
=
new
RequestResponseBodyMethodProcessor
(
Collections
.<
HttpMessageConverter
<?>>
singletonList
(
messageConverter
));
reset
(
messageConverter
);
Method
handle
=
getClass
().
getMethod
(
"handle1"
,
String
.
class
,
Integer
.
TYPE
);
paramRequestBodyString
=
new
MethodParameter
(
handle
,
0
);
paramInt
=
new
MethodParameter
(
handle
,
1
);
returnTypeString
=
new
MethodParameter
(
handle
,
-
1
);
returnTypeInt
=
new
MethodParameter
(
getClass
().
getMethod
(
"handle2"
),
-
1
);
returnTypeStringProduces
=
new
MethodParameter
(
getClass
().
getMethod
(
"handle3"
),
-
1
);
mavContainer
=
new
ModelAndViewContainer
();
servletRequest
=
new
MockHttpServletRequest
();
webRequest
=
new
ServletWebRequest
(
servletRequest
,
new
MockHttpServletResponse
());
servletResponse
=
new
MockHttpServletResponse
();
webRequest
=
new
ServletWebRequest
(
servletRequest
,
servletResponse
);
}
@Test
...
...
@@ -111,7 +113,6 @@ public class RequestResponseBodyMethodProcessorTests {
servletRequest
.
addHeader
(
"Content-Type"
,
contentType
.
toString
());
String
body
=
"Foo"
;
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
contentType
));
expect
(
messageConverter
.
canRead
(
String
.
class
,
contentType
)).
andReturn
(
true
);
expect
(
messageConverter
.
read
(
eq
(
String
.
class
),
isA
(
HttpInputMessage
.
class
))).
andReturn
(
body
);
...
...
@@ -150,6 +151,8 @@ public class RequestResponseBodyMethodProcessorTests {
servletRequest
.
addHeader
(
"Accept"
,
accepted
.
toString
());
String
body
=
"Foo"
;
expect
(
messageConverter
.
canWrite
(
String
.
class
,
null
)).
andReturn
(
true
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Collections
.
singletonList
(
MediaType
.
TEXT_PLAIN
));
expect
(
messageConverter
.
canWrite
(
String
.
class
,
accepted
)).
andReturn
(
true
);
messageConverter
.
write
(
eq
(
body
),
eq
(
accepted
),
isA
(
HttpOutputMessage
.
class
));
replay
(
messageConverter
);
...
...
@@ -160,19 +163,50 @@ public class RequestResponseBodyMethodProcessorTests {
verify
(
messageConverter
);
}
@Test
public
void
handleReturnValueProduces
()
throws
Exception
{
String
body
=
"Foo"
;
servletRequest
.
addHeader
(
"Accept"
,
"text/*"
);
expect
(
messageConverter
.
canWrite
(
String
.
class
,
MediaType
.
TEXT_HTML
)).
andReturn
(
true
);
messageConverter
.
write
(
eq
(
body
),
eq
(
MediaType
.
TEXT_HTML
),
isA
(
HttpOutputMessage
.
class
));
replay
(
messageConverter
);
processor
.
handleReturnValue
(
body
,
returnTypeStringProduces
,
mavContainer
,
webRequest
);
assertFalse
(
mavContainer
.
isResolveView
());
verify
(
messageConverter
);
}
@Test
(
expected
=
HttpMediaTypeNotAcceptableException
.
class
)
public
void
handleReturnValueNotAcceptable
()
throws
Exception
{
MediaType
accepted
=
MediaType
.
TEXT_PLAIN
;
MediaType
accepted
=
MediaType
.
APPLICATION_ATOM_XML
;
servletRequest
.
addHeader
(
"Accept"
,
accepted
.
toString
());
expect
(
messageConverter
.
canWrite
(
String
.
class
,
null
)).
andReturn
(
true
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
MediaType
.
TEXT_PLAIN
));
expect
(
messageConverter
.
canWrite
(
String
.
class
,
accepted
)).
andReturn
(
false
);
expect
(
messageConverter
.
getSupportedMediaTypes
()).
andReturn
(
Arrays
.
asList
(
MediaType
.
APPLICATION_OCTET_STREAM
));
replay
(
messageConverter
);
processor
.
handleReturnValue
(
"Foo"
,
returnTypeString
,
mavContainer
,
webRequest
);
fail
(
"Expected exception"
);
}
@Test
(
expected
=
HttpMediaTypeNotAcceptableException
.
class
)
public
void
handleReturnValueNotAcceptableProduces
()
throws
Exception
{
MediaType
accepted
=
MediaType
.
TEXT_PLAIN
;
servletRequest
.
addHeader
(
"Accept"
,
accepted
.
toString
());
expect
(
messageConverter
.
canWrite
(
String
.
class
,
accepted
)).
andReturn
(
false
);
replay
(
messageConverter
);
processor
.
handleReturnValue
(
"Foo"
,
returnTypeStringProduces
,
mavContainer
,
webRequest
);
fail
(
"Expected exception"
);
}
@ResponseBody
public
String
handle1
(
@RequestBody
String
s
,
int
i
)
{
...
...
@@ -182,5 +216,11 @@ public class RequestResponseBodyMethodProcessorTests {
public
int
handle2
()
{
return
42
;
}
@RequestMapping
(
produces
=
{
"text/html"
,
"application/xhtml+xml"
})
@ResponseBody
public
String
handle3
()
{
return
null
;
}
}
\ No newline at end of file
org.springframework.web/src/main/java/org/springframework/http/MediaType.java
浏览文件 @
ad2e0d45
...
...
@@ -322,7 +322,7 @@ public class MediaType implements Comparable<MediaType> {
}
/**
* Indicate whether the {@linkplain #getType() type} is the wildcard character <code>*</code> or not.
* Indicate
s
whether the {@linkplain #getType() type} is the wildcard character <code>*</code> or not.
*/
public
boolean
isWildcardType
()
{
return
WILDCARD_TYPE
.
equals
(
type
);
...
...
@@ -336,13 +336,22 @@ public class MediaType implements Comparable<MediaType> {
}
/**
* Indicate whether the {@linkplain #getSubtype() subtype} is the wildcard character <code>*</code> or not.
* Indicate
s
whether the {@linkplain #getSubtype() subtype} is the wildcard character <code>*</code> or not.
* @return whether the subtype is <code>*</code>
*/
public
boolean
isWildcardSubtype
()
{
return
WILDCARD_TYPE
.
equals
(
subtype
);
}
/**
* Indicates whether this media type is concrete, i.e. whether neither the type or subtype is a wildcard
* character <code>*</code>.
* @return whether this media type is concrete
*/
public
boolean
isConcrete
()
{
return
!
isWildcardType
()
&&
!
isWildcardSubtype
();
}
/**
* Return the character set, as indicated by a <code>charset</code> parameter, if any.
* @return the character set; or <code>null</code> if not available
...
...
org.springframework.web/src/main/java/org/springframework/web/HttpRequestMethodNotSupportedException.java
浏览文件 @
ad2e0d45
/*
* Copyright 2002-20
08
the original author or authors.
* Copyright 2002-20
11
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.
...
...
@@ -16,6 +16,7 @@
package
org.springframework.web
;
import
java.util.Collection
;
import
javax.servlet.ServletException
;
/**
...
...
@@ -49,6 +50,15 @@ public class HttpRequestMethodNotSupportedException extends ServletException {
this
(
method
,
supportedMethods
,
"Request method '"
+
method
+
"' not supported"
);
}
/**
* Create a new HttpRequestMethodNotSupportedException.
* @param method the unsupported HTTP request method
* @param supportedMethods the actually supported HTTP methods
*/
public
HttpRequestMethodNotSupportedException
(
String
method
,
Collection
<
String
>
supportedMethods
)
{
this
(
method
,
supportedMethods
.
toArray
(
new
String
[
supportedMethods
.
size
()]));
}
/**
* Create a new HttpRequestMethodNotSupportedException.
* @param method the unsupported HTTP request method
...
...
org.springframework.web/src/test/java/org/springframework/http/MediaTypeTests.java
浏览文件 @
ad2e0d45
...
...
@@ -16,12 +16,6 @@
package
org.springframework.http
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertSame
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
java.nio.charset.Charset
;
import
java.util.ArrayList
;
import
java.util.Collections
;
...
...
@@ -30,9 +24,12 @@ import java.util.List;
import
java.util.Random
;
import
org.junit.Test
;
import
org.springframework.core.convert.ConversionService
;
import
org.springframework.core.convert.support.DefaultConversionService
;
import
static
org
.
junit
.
Assert
.*;
/**
* @author Arjen Poutsma
* @author Juergen Hoeller
...
...
@@ -499,5 +496,14 @@ public class MediaTypeTests {
MediaType
mediaType
=
MediaType
.
parseMediaType
(
"application/xml"
);
assertEquals
(
mediaType
,
conversionService
.
convert
(
"application/xml"
,
MediaType
.
class
));
}
@Test
public
void
isConcrete
()
{
assertTrue
(
"text/plain not concrete"
,
MediaType
.
TEXT_PLAIN
.
isConcrete
());
assertFalse
(
"*/* concrete"
,
MediaType
.
ALL
.
isConcrete
());
assertFalse
(
"text/* concrete"
,
new
MediaType
(
"text"
,
"*"
).
isConcrete
());
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录