Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
a7582fcc
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,体验更适合开发者的 AI 搜索 >>
提交
a7582fcc
编写于
3月 13, 2017
作者:
R
Rossen Stoyanchev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Polish method parameter handling
上级
5ae9afd5
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
222 addition
and
293 deletion
+222
-293
spring-webflux/src/main/java/org/springframework/web/reactive/result/AbstractHandlerResultHandler.java
...ork/web/reactive/result/AbstractHandlerResultHandler.java
+10
-0
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
...hod/annotation/AbstractMessageReaderArgumentResolver.java
+10
-18
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
...method/annotation/AbstractMessageWriterResultHandler.java
+6
-8
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
.../result/method/annotation/HttpEntityArgumentResolver.java
+9
-20
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java
...thod/annotation/ModelAttributeMethodArgumentResolver.java
+21
-28
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java
...hod/annotation/PathVariableMapMethodArgumentResolver.java
+4
-3
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
...result/method/annotation/RequestBodyArgumentResolver.java
+2
-2
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
...e/result/method/annotation/ResponseBodyResultHandler.java
+13
-39
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java
...result/method/annotation/ResponseEntityResultHandler.java
+26
-44
spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java
...web/reactive/result/view/ViewResolutionResultHandler.java
+45
-65
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
...lt/method/annotation/HttpEntityArgumentResolverTests.java
+37
-38
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
...ult/method/annotation/ResponseBodyResultHandlerTests.java
+39
-28
未找到文件。
spring-webflux/src/main/java/org/springframework/web/reactive/result/AbstractHandlerResultHandler.java
浏览文件 @
a7582fcc
...
...
@@ -25,10 +25,12 @@ import java.util.Set;
import
java.util.function.Supplier
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.ReactiveAdapter
;
import
org.springframework.core.ReactiveAdapterRegistry
;
import
org.springframework.http.MediaType
;
import
org.springframework.util.Assert
;
import
org.springframework.web.reactive.HandlerMapping
;
import
org.springframework.web.reactive.HandlerResult
;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolver
;
import
org.springframework.web.server.ServerWebExchange
;
...
...
@@ -72,6 +74,14 @@ public abstract class AbstractHandlerResultHandler implements Ordered {
return
this
.
adapterRegistry
;
}
/**
* Shortcut to get a ReactiveAdapter for the top-level return value type.
*/
protected
ReactiveAdapter
getAdapter
(
HandlerResult
result
)
{
Class
<?>
returnType
=
result
.
getReturnType
().
getRawClass
();
return
getAdapterRegistry
().
getAdapter
(
returnType
,
result
.
getReturnValue
());
}
/**
* Return the configured {@link RequestedContentTypeResolver}.
*/
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
浏览文件 @
a7582fcc
...
...
@@ -113,11 +113,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
ResolvableType
bodyType
=
ResolvableType
.
forMethodParameter
(
bodyParameter
);
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
bodyType
.
resolve
());
ResolvableType
elementType
=
ResolvableType
.
forMethodParameter
(
bodyParameter
);
if
(
adapter
!=
null
)
{
elementType
=
elementType
.
getGeneric
(
0
);
}
ResolvableType
elementType
=
(
adapter
!=
null
?
bodyType
.
getGeneric
(
0
)
:
bodyType
);
ServerHttpRequest
request
=
exchange
.
getRequest
();
ServerHttpResponse
response
=
exchange
.
getResponse
();
...
...
@@ -139,8 +135,8 @@ public abstract class AbstractMessageReaderArgumentResolver {
else
{
flux
=
reader
.
read
(
elementType
,
request
,
readHints
);
}
flux
=
flux
.
onErrorResumeWith
(
ex
->
Flux
.
error
(
wrapReadError
(
ex
,
bodyParameter
)));
if
(
checkRequired
(
adapter
,
isBodyRequired
))
{
flux
=
flux
.
onErrorResumeWith
(
ex
->
Flux
.
error
(
getReadError
(
bodyParameter
,
ex
)));
if
(
isBodyRequired
||
!
adapter
.
supportsEmpty
(
))
{
flux
=
flux
.
switchIfEmpty
(
Flux
.
error
(
getRequiredBodyError
(
bodyParameter
)));
}
Object
[]
hints
=
extractValidationHints
(
bodyParameter
);
...
...
@@ -159,8 +155,8 @@ public abstract class AbstractMessageReaderArgumentResolver {
else
{
mono
=
reader
.
readMono
(
elementType
,
request
,
readHints
);
}
mono
=
mono
.
otherwise
(
ex
->
Mono
.
error
(
wrapReadError
(
ex
,
bodyParameter
)));
if
(
checkRequired
(
adapter
,
isBodyRequired
))
{
mono
=
mono
.
otherwise
(
ex
->
Mono
.
error
(
getReadError
(
bodyParameter
,
ex
)));
if
(
isBodyRequired
||
(
adapter
!=
null
&&
!
adapter
.
supportsEmpty
()
))
{
mono
=
mono
.
otherwiseIfEmpty
(
Mono
.
error
(
getRequiredBodyError
(
bodyParameter
)));
}
Object
[]
hints
=
extractValidationHints
(
bodyParameter
);
...
...
@@ -181,15 +177,11 @@ public abstract class AbstractMessageReaderArgumentResolver {
return
Mono
.
error
(
new
UnsupportedMediaTypeStatusException
(
mediaType
,
this
.
supportedMediaTypes
));
}
pr
otected
ServerWebInputException
wrapReadError
(
Throwable
ex
,
MethodParameter
parameter
)
{
pr
ivate
ServerWebInputException
getReadError
(
MethodParameter
parameter
,
Throwable
ex
)
{
return
new
ServerWebInputException
(
"Failed to read HTTP message"
,
parameter
,
ex
);
}
protected
boolean
checkRequired
(
ReactiveAdapter
adapter
,
boolean
isBodyRequired
)
{
return
adapter
!=
null
&&
!
adapter
.
supportsEmpty
()
||
isBodyRequired
;
}
protected
ServerWebInputException
getRequiredBodyError
(
MethodParameter
parameter
)
{
private
ServerWebInputException
getRequiredBodyError
(
MethodParameter
parameter
)
{
return
new
ServerWebInputException
(
"Required request body is missing: "
+
parameter
.
getMethod
().
toGenericString
());
}
...
...
@@ -199,7 +191,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
* a (possibly empty) Object[] with validation hints. A return value of
* {@code null} indicates that validation is not required.
*/
pr
otected
Object
[]
extractValidationHints
(
MethodParameter
parameter
)
{
pr
ivate
Object
[]
extractValidationHints
(
MethodParameter
parameter
)
{
Annotation
[]
annotations
=
parameter
.
getParameterAnnotations
();
for
(
Annotation
ann
:
annotations
)
{
Validated
validAnnot
=
AnnotationUtils
.
getAnnotation
(
ann
,
Validated
.
class
);
...
...
@@ -211,8 +203,8 @@ public abstract class AbstractMessageReaderArgumentResolver {
return
null
;
}
pr
otected
void
validate
(
Object
target
,
Object
[]
validationHints
,
MethodParameter
param
,
BindingContext
binding
,
ServerWebExchange
exchange
)
{
pr
ivate
void
validate
(
Object
target
,
Object
[]
validationHints
,
MethodParameter
param
,
BindingContext
binding
,
ServerWebExchange
exchange
)
{
String
name
=
Conventions
.
getVariableNameForParameter
(
param
);
WebExchangeDataBinder
binder
=
binding
.
createDataBinder
(
exchange
,
target
,
name
);
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
浏览文件 @
a7582fcc
...
...
@@ -93,21 +93,19 @@ public abstract class AbstractMessageWriterResultHandler extends AbstractHandler
@SuppressWarnings
(
"unchecked"
)
protected
Mono
<
Void
>
writeBody
(
Object
body
,
MethodParameter
bodyParameter
,
ServerWebExchange
exchange
)
{
ResolvableType
value
Type
=
ResolvableType
.
forMethodParameter
(
bodyParameter
);
Class
<?>
valueClass
=
value
Type
.
resolve
();
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
value
Class
,
body
);
ResolvableType
body
Type
=
ResolvableType
.
forMethodParameter
(
bodyParameter
);
Class
<?>
bodyClass
=
body
Type
.
resolve
();
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
body
Class
,
body
);
Publisher
<?>
publisher
;
ResolvableType
elementType
;
if
(
adapter
!=
null
)
{
publisher
=
adapter
.
toPublisher
(
body
);
elementType
=
adapter
.
isNoValue
()
?
ResolvableType
.
forClass
(
Void
.
class
)
:
valueType
.
getGeneric
(
0
);
elementType
=
adapter
.
isNoValue
()
?
ResolvableType
.
forClass
(
Void
.
class
)
:
bodyType
.
getGeneric
(
0
);
}
else
{
publisher
=
Mono
.
justOrEmpty
(
body
);
elementType
=
(
valueClass
==
null
&&
body
!=
null
?
ResolvableType
.
forInstance
(
body
)
:
valueType
);
elementType
=
(
bodyClass
==
null
&&
body
!=
null
?
ResolvableType
.
forInstance
(
body
)
:
bodyType
);
}
if
(
void
.
class
==
elementType
.
getRawClass
()
||
Void
.
class
==
elementType
.
getRawClass
())
{
...
...
@@ -122,7 +120,7 @@ public abstract class AbstractMessageWriterResultHandler extends AbstractHandler
if
(
messageWriter
.
canWrite
(
elementType
,
bestMediaType
))
{
return
(
messageWriter
instanceof
ServerHttpMessageWriter
?
((
ServerHttpMessageWriter
<?>)
messageWriter
).
write
((
Publisher
)
publisher
,
value
Type
,
elementType
,
bestMediaType
,
request
,
response
,
Collections
.
emptyMap
())
:
body
Type
,
elementType
,
bestMediaType
,
request
,
response
,
Collections
.
emptyMap
())
:
messageWriter
.
write
((
Publisher
)
publisher
,
elementType
,
bestMediaType
,
response
,
Collections
.
emptyMap
()));
}
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
浏览文件 @
a7582fcc
...
...
@@ -22,9 +22,7 @@ import reactor.core.publisher.Mono;
import
org.springframework.core.MethodParameter
;
import
org.springframework.core.ReactiveAdapterRegistry
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.RequestEntity
;
import
org.springframework.http.codec.HttpMessageReader
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
...
...
@@ -69,29 +67,20 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes
}
@Override
public
Mono
<
Object
>
resolveArgument
(
MethodParameter
param
,
BindingContext
bindingContext
,
public
Mono
<
Object
>
resolveArgument
(
MethodParameter
param
eter
,
BindingContext
bindingContext
,
ServerWebExchange
exchange
)
{
ResolvableType
entityType
=
ResolvableType
.
forMethodParameter
(
param
);
MethodParameter
bodyParameter
=
new
MethodParameter
(
param
);
bodyParameter
.
increaseNestingLevel
();
Class
<?>
entityType
=
parameter
.
getParameterType
();
return
readBody
(
bodyParameter
,
false
,
bindingContext
,
exchange
)
.
map
(
body
->
create
HttpEntity
(
body
,
entityType
,
exchange
))
.
defaultIfEmpty
(
create
HttpEntity
(
null
,
entityType
,
exchange
));
return
readBody
(
parameter
.
nested
()
,
false
,
bindingContext
,
exchange
)
.
map
(
body
->
create
Entity
(
body
,
entityType
,
exchange
.
getRequest
()
))
.
defaultIfEmpty
(
create
Entity
(
null
,
entityType
,
exchange
.
getRequest
()
));
}
private
Object
createHttpEntity
(
Object
body
,
ResolvableType
entityType
,
ServerWebExchange
exchange
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
HttpHeaders
headers
=
request
.
getHeaders
();
if
(
RequestEntity
.
class
==
entityType
.
getRawClass
())
{
return
new
RequestEntity
<>(
body
,
headers
,
request
.
getMethod
(),
request
.
getURI
());
}
else
{
return
new
HttpEntity
<>(
body
,
headers
);
}
private
Object
createEntity
(
Object
body
,
Class
<?>
entityType
,
ServerHttpRequest
request
)
{
return
RequestEntity
.
class
.
equals
(
entityType
)
?
new
RequestEntity
<>(
body
,
request
.
getHeaders
(),
request
.
getMethod
(),
request
.
getURI
())
:
new
HttpEntity
<>(
body
,
request
.
getHeaders
());
}
}
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java
浏览文件 @
a7582fcc
...
...
@@ -28,6 +28,7 @@ import org.springframework.core.ReactiveAdapter;
import
org.springframework.core.ReactiveAdapterRegistry
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.core.annotation.AnnotationUtils
;
import
org.springframework.ui.Model
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.StringUtils
;
...
...
@@ -122,9 +123,10 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
ResolvableType
type
=
ResolvableType
.
forMethodParameter
(
parameter
);
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
type
.
resolve
());
Class
<?>
valueType
=
(
adapter
!=
null
?
type
.
resolveGeneric
(
0
)
:
parameter
.
getParameterType
());
ResolvableType
valueType
=
(
adapter
!=
null
?
type
.
getGeneric
(
0
)
:
type
);
String
name
=
getAttributeName
(
valueType
,
parameter
);
Mono
<?>
valueMono
=
getAttributeMono
(
name
,
valueType
,
parameter
,
context
,
exchange
);
Mono
<?>
valueMono
=
getAttributeMono
(
name
,
valueType
,
context
.
getModel
()
);
Map
<
String
,
Object
>
model
=
context
.
getModel
().
asMap
();
MonoProcessor
<
BindingResult
>
bindingResultMono
=
MonoProcessor
.
create
();
...
...
@@ -146,10 +148,10 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
if
(
adapter
!=
null
)
{
return
adapter
.
fromPublisher
(
errors
.
hasErrors
()
?
Mono
.
error
(
new
WebExchangeBindException
(
parameter
,
errors
))
:
Mono
.
just
(
value
)
);
valueMono
);
}
else
{
if
(
errors
.
hasErrors
()
&&
check
ErrorsArgument
(
parameter
))
{
if
(
errors
.
hasErrors
()
&&
!
has
ErrorsArgument
(
parameter
))
{
throw
new
WebExchangeBindException
(
parameter
,
errors
);
}
return
value
;
...
...
@@ -158,46 +160,37 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
});
}
private
String
getAttributeName
(
Class
<?>
valueType
,
MethodParameter
parameter
)
{
private
String
getAttributeName
(
ResolvableType
valueType
,
MethodParameter
parameter
)
{
ModelAttribute
annot
=
parameter
.
getParameterAnnotation
(
ModelAttribute
.
class
);
if
(
annot
!=
null
&&
StringUtils
.
hasText
(
annot
.
value
()))
{
return
annot
.
value
();
}
// TODO: Conventions does not deal with async wrappers
return
ClassUtils
.
getShortNameAsProperty
(
valueType
);
return
ClassUtils
.
getShortNameAsProperty
(
valueType
.
getRawClass
()
);
}
private
Mono
<?>
getAttributeMono
(
String
attributeName
,
Class
<?>
attributeType
,
MethodParameter
param
,
BindingContext
context
,
ServerWebExchange
exchange
)
{
Object
attribute
=
context
.
getModel
().
asMap
().
get
(
attributeName
);
private
Mono
<?>
getAttributeMono
(
String
attributeName
,
ResolvableType
attributeType
,
Model
model
)
{
Object
attribute
=
model
.
asMap
().
get
(
attributeName
);
if
(
attribute
==
null
)
{
attribute
=
createAttribute
(
attributeName
,
attributeType
,
param
,
context
,
exchange
);
attribute
=
BeanUtils
.
instantiateClass
(
attributeType
.
getRawClass
()
);
}
if
(
attribute
!=
null
)
{
ReactiveAdapter
adapterFrom
=
getAdapterRegistry
().
getAdapter
(
null
,
attribute
);
if
(
adapterFrom
!=
null
)
{
Assert
.
isTrue
(!
adapterFrom
.
isMultiValue
(),
"Data binding supports single-value async types."
);
return
Mono
.
from
(
adapterFrom
.
toPublisher
(
attribute
));
}
ReactiveAdapter
adapterFrom
=
getAdapterRegistry
().
getAdapter
(
null
,
attribute
);
if
(
adapterFrom
!=
null
)
{
Assert
.
isTrue
(!
adapterFrom
.
isMultiValue
(),
"Data binding supports single-value async types."
);
return
Mono
.
from
(
adapterFrom
.
toPublisher
(
attribute
));
}
else
{
return
Mono
.
justOrEmpty
(
attribute
);
}
return
Mono
.
justOrEmpty
(
attribute
);
}
protected
Object
createAttribute
(
String
attributeName
,
Class
<?>
attributeType
,
MethodParameter
parameter
,
BindingContext
context
,
ServerWebExchange
exchange
)
{
return
BeanUtils
.
instantiateClass
(
attributeType
);
}
pr
otected
boolean
check
ErrorsArgument
(
MethodParameter
methodParam
)
{
pr
ivate
boolean
has
ErrorsArgument
(
MethodParameter
methodParam
)
{
int
i
=
methodParam
.
getParameterIndex
();
Class
<?>[]
paramTypes
=
methodParam
.
getMethod
().
getParameterTypes
();
return
paramTypes
.
length
<=
(
i
+
1
)
||
!
Errors
.
class
.
isAssignableFrom
(
paramTypes
[
i
+
1
]);
return
paramTypes
.
length
>
i
&&
Errors
.
class
.
isAssignableFrom
(
paramTypes
[
i
+
1
]);
}
pr
otected
void
validateIfApplicable
(
WebExchangeDataBinder
binder
,
MethodParameter
parameter
)
{
pr
ivate
void
validateIfApplicable
(
WebExchangeDataBinder
binder
,
MethodParameter
parameter
)
{
Annotation
[]
annotations
=
parameter
.
getParameterAnnotations
();
for
(
Annotation
ann
:
annotations
)
{
Validated
validAnnot
=
AnnotationUtils
.
getAnnotation
(
ann
,
Validated
.
class
);
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java
浏览文件 @
a7582fcc
...
...
@@ -43,9 +43,10 @@ public class PathVariableMapMethodArgumentResolver implements SyncHandlerMethodA
@Override
public
boolean
supportsParameter
(
MethodParameter
parameter
)
{
PathVariable
ann
=
parameter
.
getParameterAnnotation
(
PathVariable
.
class
);
return
(
ann
!=
null
&&
(
Map
.
class
.
isAssignableFrom
(
parameter
.
getParameterType
()))
&&
!
StringUtils
.
hasText
(
ann
.
value
()));
PathVariable
annotation
=
parameter
.
getParameterAnnotation
(
PathVariable
.
class
);
return
(
annotation
!=
null
&&
Map
.
class
.
isAssignableFrom
(
parameter
.
getParameterType
())
&&
!
StringUtils
.
hasText
(
annotation
.
value
()));
}
@Override
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
浏览文件 @
a7582fcc
...
...
@@ -74,8 +74,8 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe
public
Mono
<
Object
>
resolveArgument
(
MethodParameter
param
,
BindingContext
bindingContext
,
ServerWebExchange
exchange
)
{
boolean
isRequired
=
param
.
getParameterAnnotation
(
RequestBody
.
class
).
required
(
);
return
readBody
(
param
,
isRequired
,
bindingContext
,
exchange
);
RequestBody
annotation
=
param
.
getParameterAnnotation
(
RequestBody
.
class
);
return
readBody
(
param
,
annotation
.
required
()
,
bindingContext
,
exchange
);
}
}
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
浏览文件 @
a7582fcc
...
...
@@ -55,31 +55,26 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
/**
* Constructor with {@link HttpMessageWriter}s and a
* {@code RequestedContentTypeResolver}.
*
* @param messageWriters writers for serializing to the response body stream
* @param contentTypeResolver for resolving the requested content type
* Basic constructor with a default {@link ReactiveAdapterRegistry}.
* @param writers writers for serializing to the response body
* @param resolver to determine the requested content type
*/
public
ResponseBodyResultHandler
(
List
<
HttpMessageWriter
<?>>
messageW
riters
,
RequestedContentTypeResolver
contentTypeR
esolver
)
{
public
ResponseBodyResultHandler
(
List
<
HttpMessageWriter
<?>>
w
riters
,
RequestedContentTypeResolver
r
esolver
)
{
this
(
messageWriters
,
contentTypeR
esolver
,
new
ReactiveAdapterRegistry
());
this
(
writers
,
r
esolver
,
new
ReactiveAdapterRegistry
());
}
/**
* Constructor with an additional {@link ReactiveAdapterRegistry}.
*
* @param messageWriters writers for serializing to the response body stream
* @param contentTypeResolver for resolving the requested content type
* @param adapterRegistry for adapting other reactive types (e.g. rx.Observable,
* rx.Single, etc.) to Flux or Mono
* Constructor with an {@link ReactiveAdapterRegistry} instance.
* @param writers writers for serializing to the response body
* @param resolver to determine the requested content type
* @param registry for adaptation to reactive types
*/
public
ResponseBodyResultHandler
(
List
<
HttpMessageWriter
<?>>
messageWriters
,
RequestedContentTypeResolver
contentTypeResolver
,
ReactiveAdapterRegistry
adapterRegistry
)
{
public
ResponseBodyResultHandler
(
List
<
HttpMessageWriter
<?>>
writers
,
RequestedContentTypeResolver
resolver
,
ReactiveAdapterRegistry
registry
)
{
super
(
messageWriters
,
contentTypeResolver
,
adapterR
egistry
);
super
(
writers
,
resolver
,
r
egistry
);
setOrder
(
100
);
}
...
...
@@ -87,32 +82,11 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
@Override
public
boolean
supports
(
HandlerResult
result
)
{
MethodParameter
parameter
=
result
.
getReturnTypeSource
();
return
hasResponseBodyAnnotation
(
parameter
)
&&
!
isHttpEntityType
(
result
);
}
private
boolean
hasResponseBodyAnnotation
(
MethodParameter
parameter
)
{
Class
<?>
containingClass
=
parameter
.
getContainingClass
();
return
(
AnnotationUtils
.
findAnnotation
(
containingClass
,
ResponseBody
.
class
)
!=
null
||
parameter
.
getMethodAnnotation
(
ResponseBody
.
class
)
!=
null
);
}
private
boolean
isHttpEntityType
(
HandlerResult
result
)
{
Class
<?>
rawClass
=
result
.
getReturnType
().
getRawClass
();
if
(
HttpEntity
.
class
.
isAssignableFrom
(
rawClass
))
{
return
true
;
}
else
{
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
rawClass
,
result
.
getReturnValue
());
if
(
adapter
!=
null
&&
!
adapter
.
isNoValue
())
{
ResolvableType
genericType
=
result
.
getReturnType
().
getGeneric
(
0
);
if
(
HttpEntity
.
class
.
isAssignableFrom
(
genericType
.
getRawClass
()))
{
return
true
;
}
}
}
return
false
;
}
@Override
public
Mono
<
Void
>
handleResult
(
ServerWebExchange
exchange
,
HandlerResult
result
)
{
Object
body
=
result
.
getReturnValue
().
orElse
(
null
);
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java
浏览文件 @
a7582fcc
...
...
@@ -18,7 +18,6 @@ package org.springframework.web.reactive.result.method.annotation;
import
java.time.Instant
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Optional
;
import
reactor.core.publisher.Mono
;
...
...
@@ -54,78 +53,61 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
/**
* Constructor with {@link HttpMessageWriter}s and a
* {@code RequestedContentTypeResolver}.
*
* @param messageWriters writers for serializing to the response body stream
* @param contentTypeResolver for resolving the requested content type
* Basic constructor with a default {@link ReactiveAdapterRegistry}.
* @param writers writers for serializing to the response body
* @param resolver to determine the requested content type
*/
public
ResponseEntityResultHandler
(
List
<
HttpMessageWriter
<?>>
messageW
riters
,
RequestedContentTypeResolver
contentTypeR
esolver
)
{
public
ResponseEntityResultHandler
(
List
<
HttpMessageWriter
<?>>
w
riters
,
RequestedContentTypeResolver
r
esolver
)
{
this
(
messageWriters
,
contentTypeR
esolver
,
new
ReactiveAdapterRegistry
());
this
(
writers
,
r
esolver
,
new
ReactiveAdapterRegistry
());
}
/**
* Constructor with an additional {@link ReactiveAdapterRegistry}.
*
* @param messageWriters writers for serializing to the response body stream
* @param contentTypeResolver for resolving the requested content type
* @param adapterRegistry for adapting other reactive types (e.g. rx.Observable,
* rx.Single, etc.) to Flux or Mono
* Constructor with an {@link ReactiveAdapterRegistry} instance.
* @param writers writers for serializing to the response body
* @param resolver to determine the requested content type
* @param registry for adaptation to reactive types
*/
public
ResponseEntityResultHandler
(
List
<
HttpMessageWriter
<?>>
messageWriters
,
RequestedContentTypeResolver
contentTypeResolver
,
ReactiveAdapterRegistry
adapterRegistry
)
{
public
ResponseEntityResultHandler
(
List
<
HttpMessageWriter
<?>>
writers
,
RequestedContentTypeResolver
resolver
,
ReactiveAdapterRegistry
registry
)
{
super
(
messageWriters
,
contentTypeResolver
,
adapterR
egistry
);
super
(
writers
,
resolver
,
r
egistry
);
setOrder
(
0
);
}
@Override
public
boolean
supports
(
HandlerResult
result
)
{
Class
<?>
returnType
=
result
.
getReturnType
().
getRawClass
();
if
(
isSupportedType
(
returnType
))
{
if
(
isSupportedType
(
result
.
getReturnType
()))
{
return
true
;
}
else
{
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
returnType
,
result
.
getReturnValue
());
if
(
adapter
!=
null
&&
!
adapter
.
isMultiValue
()
&&
!
adapter
.
isNoValue
())
{
ResolvableType
genericType
=
result
.
getReturnType
().
getGeneric
(
0
);
return
isSupportedType
(
genericType
.
getRawClass
());
}
}
return
false
;
ReactiveAdapter
adapter
=
getAdapter
(
result
);
return
adapter
!=
null
&&
!
adapter
.
isNoValue
()
&&
isSupportedType
(
result
.
getReturnType
().
getGeneric
(
0
));
}
private
boolean
isSupportedType
(
Class
<?>
clazz
)
{
private
boolean
isSupportedType
(
ResolvableType
type
)
{
Class
<?>
clazz
=
type
.
getRawClass
();
return
(
HttpEntity
.
class
.
isAssignableFrom
(
clazz
)
&&
!
RequestEntity
.
class
.
isAssignableFrom
(
clazz
));
}
@Override
public
Mono
<
Void
>
handleResult
(
ServerWebExchange
exchange
,
HandlerResult
result
)
{
ResolvableType
returnType
=
result
.
getReturnType
();
MethodParameter
bodyType
;
Mono
<?>
returnValueMono
;
Optional
<
Object
>
optionalValue
=
result
.
getReturnValue
();
Class
<?>
rawClass
=
returnType
.
getRawClass
();
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
rawClass
,
optionalValue
);
MethodParameter
bodyParameter
;
ReactiveAdapter
adapter
=
getAdapter
(
result
);
if
(
adapter
!=
null
)
{
Assert
.
isTrue
(!
adapter
.
isMultiValue
(),
"Only a single ResponseEntity supported"
);
returnValueMono
=
Mono
.
from
(
adapter
.
toPublisher
(
optionalValue
));
bodyType
=
new
MethodParameter
(
result
.
getReturnTypeSource
());
bodyType
.
increaseNestingLevel
();
bodyType
.
increaseNestingLevel
();
returnValueMono
=
Mono
.
from
(
adapter
.
toPublisher
(
result
.
getReturnValue
()));
bodyParameter
=
result
.
getReturnTypeSource
().
nested
().
nested
();
}
else
{
returnValueMono
=
Mono
.
justOrEmpty
(
optionalValue
);
bodyType
=
new
MethodParameter
(
result
.
getReturnTypeSource
());
bodyType
.
increaseNestingLevel
();
returnValueMono
=
Mono
.
justOrEmpty
(
result
.
getReturnValue
());
bodyParameter
=
result
.
getReturnTypeSource
().
nested
();
}
return
returnValueMono
.
then
(
returnValue
->
{
...
...
@@ -156,7 +138,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
return
exchange
.
getResponse
().
setComplete
();
}
return
writeBody
(
httpEntity
.
getBody
(),
body
Type
,
exchange
);
return
writeBody
(
httpEntity
.
getBody
(),
body
Parameter
,
exchange
);
});
}
...
...
spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java
浏览文件 @
a7582fcc
...
...
@@ -22,7 +22,6 @@ import java.util.Collections;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.stream.Collectors
;
import
reactor.core.publisher.Flux
;
...
...
@@ -94,29 +93,27 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
/**
*
Constructor with {@link ViewResolver}s and a {@link RequestedContentTypeResolver
}.
* @param
r
esolvers the resolver to use
* @param contentTypeResolver
for resolving
the requested content type
*
Basic constructor with a default {@link ReactiveAdapterRegistry
}.
* @param
viewR
esolvers the resolver to use
* @param contentTypeResolver
to determine
the requested content type
*/
public
ViewResolutionResultHandler
(
List
<
ViewResolver
>
r
esolvers
,
public
ViewResolutionResultHandler
(
List
<
ViewResolver
>
viewR
esolvers
,
RequestedContentTypeResolver
contentTypeResolver
)
{
this
(
r
esolvers
,
contentTypeResolver
,
new
ReactiveAdapterRegistry
());
this
(
viewR
esolvers
,
contentTypeResolver
,
new
ReactiveAdapterRegistry
());
}
/**
* Constructor with {@code ViewResolver}s tand a {@code ConversionService}.
* @param resolvers the resolver to use
* @param contentTypeResolver for resolving the requested content type
* @param adapterRegistry for adapting from other reactive types (e.g.
* rx.Single) to Mono
* Constructor with an {@link ReactiveAdapterRegistry} instance.
* @param viewResolvers the view resolver to use
* @param contentTypeResolver to determine the requested content type
* @param registry for adaptation to reactive types
*/
public
ViewResolutionResultHandler
(
List
<
ViewResolver
>
resolvers
,
RequestedContentTypeResolver
contentTypeResolver
,
ReactiveAdapterRegistry
adapterRegistry
)
{
public
ViewResolutionResultHandler
(
List
<
ViewResolver
>
viewResolvers
,
RequestedContentTypeResolver
contentTypeResolver
,
ReactiveAdapterRegistry
registry
)
{
super
(
contentTypeResolver
,
adapterR
egistry
);
this
.
viewResolvers
.
addAll
(
r
esolvers
);
super
(
contentTypeResolver
,
r
egistry
);
this
.
viewResolvers
.
addAll
(
viewR
esolvers
);
AnnotationAwareOrderComparator
.
sort
(
this
.
viewResolvers
);
}
...
...
@@ -148,113 +145,97 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
@Override
public
boolean
supports
(
HandlerResult
result
)
{
Class
<?>
clazz
=
result
.
getReturnType
().
getRawClass
();
if
(
hasModelAttributeAnnotation
(
result
))
{
if
(
hasModelAnnotation
(
result
.
getReturnTypeSource
()))
{
return
true
;
}
Optional
<
Object
>
optional
=
result
.
getReturnValue
();
ReactiveAdapter
adapter
=
getAdapter
Registry
().
getAdapter
(
clazz
,
optional
);
Class
<?>
type
=
result
.
getReturnType
().
getRawClass
();
ReactiveAdapter
adapter
=
getAdapter
(
result
);
if
(
adapter
!=
null
)
{
if
(
adapter
.
isNoValue
())
{
return
true
;
}
else
{
clazz
=
result
.
getReturnType
().
getGeneric
(
0
).
getRawClass
();
return
isSupportedType
(
clazz
);
}
}
else
if
(
isSupportedType
(
clazz
))
{
return
true
;
type
=
result
.
getReturnType
().
getGeneric
(
0
).
getRawClass
();
}
return
false
;
return
(
CharSequence
.
class
.
isAssignableFrom
(
type
)
||
View
.
class
.
isAssignableFrom
(
type
)
||
Model
.
class
.
isAssignableFrom
(
type
)
||
Map
.
class
.
isAssignableFrom
(
type
)
||
!
BeanUtils
.
isSimpleProperty
(
type
));
}
private
boolean
hasModelAttributeAnnotation
(
HandlerResult
result
)
{
MethodParameter
returnType
=
result
.
getReturnTypeSource
();
return
returnType
.
hasMethodAnnotation
(
ModelAttribute
.
class
);
}
private
boolean
isSupportedType
(
Class
<?>
clazz
)
{
return
(
CharSequence
.
class
.
isAssignableFrom
(
clazz
)
||
View
.
class
.
isAssignableFrom
(
clazz
)
||
Model
.
class
.
isAssignableFrom
(
clazz
)
||
Map
.
class
.
isAssignableFrom
(
clazz
)
||
!
BeanUtils
.
isSimpleProperty
(
clazz
));
private
boolean
hasModelAnnotation
(
MethodParameter
parameter
)
{
return
parameter
.
hasMethodAnnotation
(
ModelAttribute
.
class
);
}
@Override
@SuppressWarnings
(
"unchecked"
)
public
Mono
<
Void
>
handleResult
(
ServerWebExchange
exchange
,
HandlerResult
result
)
{
Mono
<
Object
>
returnValueMono
;
ResolvableType
elementType
;
ResolvableType
parameterType
=
result
.
getReturnType
();
Optional
<
Object
>
optional
=
result
.
getReturnValue
();
ReactiveAdapter
adapter
=
getAdapterRegistry
().
getAdapter
(
parameterType
.
getRawClass
(),
optional
);
Mono
<
Object
>
valueMono
;
ResolvableType
valueType
;
ReactiveAdapter
adapter
=
getAdapter
(
result
);
if
(
adapter
!=
null
)
{
Assert
.
isTrue
(!
adapter
.
isMultiValue
(),
"Only single-value async return type supported."
);
returnValueMono
=
optional
.
map
(
value
->
Mono
.
from
(
adapter
.
toPublisher
(
value
)))
.
orElse
(
Mono
.
empty
());
elementType
=
!
adapter
.
isNoValue
()
?
parameterType
.
getGeneric
(
0
)
:
ResolvableType
.
forClass
(
Void
.
class
);
valueMono
=
result
.
getReturnValue
()
.
map
(
value
->
Mono
.
from
(
adapter
.
toPublisher
(
value
))).
orElse
(
Mono
.
empty
());
valueType
=
adapter
.
isNoValue
()
?
ResolvableType
.
forClass
(
Void
.
class
)
:
result
.
getReturnType
().
getGeneric
(
0
);
}
else
{
returnV
alueMono
=
Mono
.
justOrEmpty
(
result
.
getReturnValue
());
elementType
=
parameterType
;
v
alueMono
=
Mono
.
justOrEmpty
(
result
.
getReturnValue
());
valueType
=
result
.
getReturnType
()
;
}
return
returnV
alueMono
return
v
alueMono
.
otherwiseIfEmpty
(
exchange
.
isNotModified
()
?
Mono
.
empty
()
:
NO_VALUE_MONO
)
.
then
(
returnValue
->
{
Mono
<
List
<
View
>>
viewsMono
;
Model
model
=
result
.
getModel
();
MethodParameter
parameter
=
result
.
getReturnTypeSource
();
Locale
acceptLocale
=
exchange
.
getRequest
().
getHeaders
().
getAcceptLanguageAsLocale
();
Locale
locale
=
acceptLocale
!=
null
?
acceptLocale
:
Locale
.
getDefault
();
Class
<?>
clazz
=
element
Type
.
getRawClass
();
Class
<?>
clazz
=
value
Type
.
getRawClass
();
if
(
clazz
==
null
)
{
clazz
=
returnValue
.
getClass
();
}
if
(
returnValue
==
NO_VALUE
||
Void
.
class
.
equals
(
clazz
)
||
void
.
class
.
equals
(
clazz
))
{
viewsMono
=
resolveViews
(
getDefaultViewName
(
result
,
exchange
),
locale
);
viewsMono
=
resolveViews
(
getDefaultViewName
(
exchange
),
locale
);
}
else
if
(
Model
.
class
.
isAssignableFrom
(
clazz
))
{
model
.
addAllAttributes
(((
Model
)
returnValue
).
asMap
());
viewsMono
=
resolveViews
(
getDefaultViewName
(
result
,
exchange
),
locale
);
viewsMono
=
resolveViews
(
getDefaultViewName
(
exchange
),
locale
);
}
else
if
(
Map
.
class
.
isAssignableFrom
(
clazz
))
{
model
.
addAllAttributes
((
Map
<
String
,
?>)
returnValue
);
viewsMono
=
resolveViews
(
getDefaultViewName
(
result
,
exchange
),
locale
);
viewsMono
=
resolveViews
(
getDefaultViewName
(
exchange
),
locale
);
}
else
if
(
View
.
class
.
isAssignableFrom
(
clazz
))
{
viewsMono
=
Mono
.
just
(
Collections
.
singletonList
((
View
)
returnValue
));
}
else
if
(
CharSequence
.
class
.
isAssignableFrom
(
clazz
)
&&
!
hasModelA
ttributeAnnotation
(
result
))
{
else
if
(
CharSequence
.
class
.
isAssignableFrom
(
clazz
)
&&
!
hasModelA
nnotation
(
parameter
))
{
viewsMono
=
resolveViews
(
returnValue
.
toString
(),
locale
);
}
else
{
String
name
=
getNameForReturnValue
(
clazz
,
result
.
getReturnTypeSource
()
);
String
name
=
getNameForReturnValue
(
clazz
,
parameter
);
model
.
addAttribute
(
name
,
returnValue
);
viewsMono
=
resolveViews
(
getDefaultViewName
(
result
,
exchange
),
locale
);
viewsMono
=
resolveViews
(
getDefaultViewName
(
exchange
),
locale
);
}
return
resolveAsyncAttributes
(
model
.
asMap
())
.
doOnSuccess
(
aVoid
->
addBindingResult
(
result
,
exchange
))
.
doOnSuccess
(
aVoid
->
addBindingResult
(
result
.
getBindingContext
()
,
exchange
))
.
then
(
viewsMono
)
.
then
(
views
->
render
(
views
,
model
.
asMap
(),
exchange
));
});
}
/**
* Select a default view name when a controller leaves the view unspecified.
* The default implementation strips the leading and trailing slash from the
* as well as any extension and uses that as the view name.
* Select a default view name when a controller did not specify it.
* Use the request path the leading and trailing slash stripped.
*/
pr
otected
String
getDefaultViewName
(
HandlerResult
result
,
ServerWebExchange
exchange
)
{
pr
ivate
String
getDefaultViewName
(
ServerWebExchange
exchange
)
{
String
path
=
this
.
pathHelper
.
getLookupPathForRequest
(
exchange
);
if
(
path
.
startsWith
(
"/"
))
{
path
=
path
.
substring
(
1
);
...
...
@@ -332,8 +313,7 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
.
then
();
}
private
void
addBindingResult
(
HandlerResult
result
,
ServerWebExchange
exchange
)
{
BindingContext
context
=
result
.
getBindingContext
();
private
void
addBindingResult
(
BindingContext
context
,
ServerWebExchange
exchange
)
{
Map
<
String
,
Object
>
model
=
context
.
getModel
().
asMap
();
model
.
keySet
().
stream
()
.
filter
(
name
->
isBindingCandidate
(
name
,
model
.
get
(
name
)))
...
...
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
浏览文件 @
a7582fcc
...
...
@@ -43,6 +43,7 @@ import org.springframework.http.codec.DecoderHttpMessageReader;
import
org.springframework.http.codec.HttpMessageReader
;
import
org.springframework.mock.http.server.reactive.test.MockServerHttpRequest
;
import
org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.web.reactive.BindingContext
;
import
org.springframework.web.method.ResolvableMethod
;
import
org.springframework.web.server.ServerWebExchange
;
...
...
@@ -83,23 +84,26 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
supports
()
throws
Exception
{
testSupports
(
httpEntityType
(
String
.
class
));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
Mono
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
Single
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
io
.
reactivex
.
Single
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
Maybe
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
CompletableFuture
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
Flux
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
Observable
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
io
.
reactivex
.
Observable
.
class
,
String
.
class
)));
testSupports
(
httpEntityType
(
forClassWithGenerics
(
Flowable
.
class
,
String
.
class
)));
testSupports
(
forClassWithGenerics
(
RequestEntity
.
class
,
String
.
class
));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
Mono
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
Single
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
io
.
reactivex
.
Single
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
Maybe
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
CompletableFuture
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
Flux
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
Observable
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
io
.
reactivex
.
Observable
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
httpEntityType
(
Flowable
.
class
,
String
.
class
)));
testSupports
(
this
.
testMethod
.
arg
(
forClassWithGenerics
(
RequestEntity
.
class
,
String
.
class
)));
}
private
void
testSupports
(
MethodParameter
parameter
)
{
assertTrue
(
this
.
resolver
.
supportsParameter
(
parameter
));
}
@Test
public
void
doesNotSupport
()
throws
Exception
{
ResolvableType
type
=
ResolvableType
.
forClassWithGenerics
(
Mono
.
class
,
String
.
class
);
assertFalse
(
this
.
resolver
.
supportsParameter
(
this
.
testMethod
.
arg
(
type
)));
assertFalse
(
this
.
resolver
.
supportsParameter
(
this
.
testMethod
.
arg
(
Mono
.
class
,
String
.
class
)));
assertFalse
(
this
.
resolver
.
supportsParameter
(
this
.
testMethod
.
arg
(
String
.
class
)));
}
...
...
@@ -113,7 +117,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithMono
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Mono
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Mono
.
class
,
String
.
class
);
HttpEntity
<
Mono
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
entity
.
getBody
()).
expectNextCount
(
0
).
expectComplete
().
verify
();
...
...
@@ -121,7 +125,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithFlux
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Flux
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Flux
.
class
,
String
.
class
);
HttpEntity
<
Flux
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
entity
.
getBody
()).
expectNextCount
(
0
).
expectComplete
().
verify
();
...
...
@@ -129,7 +133,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithSingle
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Single
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Single
.
class
,
String
.
class
);
HttpEntity
<
Single
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
RxReactiveStreams
.
toPublisher
(
entity
.
getBody
()))
...
...
@@ -140,7 +144,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithRxJava2Single
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
io
.
reactivex
.
Single
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
io
.
reactivex
.
Single
.
class
,
String
.
class
);
HttpEntity
<
io
.
reactivex
.
Single
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
entity
.
getBody
().
toFlowable
())
...
...
@@ -151,7 +155,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithRxJava2Maybe
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Maybe
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Maybe
.
class
,
String
.
class
);
HttpEntity
<
Maybe
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
entity
.
getBody
().
toFlowable
())
...
...
@@ -162,7 +166,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithObservable
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Observable
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Observable
.
class
,
String
.
class
);
HttpEntity
<
Observable
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
RxReactiveStreams
.
toPublisher
(
entity
.
getBody
()))
...
...
@@ -173,7 +177,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithRxJava2Observable
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
io
.
reactivex
.
Observable
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
io
.
reactivex
.
Observable
.
class
,
String
.
class
);
HttpEntity
<
io
.
reactivex
.
Observable
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
entity
.
getBody
().
toFlowable
(
BackpressureStrategy
.
BUFFER
))
...
...
@@ -184,7 +188,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithFlowable
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Flowable
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Flowable
.
class
,
String
.
class
);
HttpEntity
<
Flowable
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
StepVerifier
.
create
(
entity
.
getBody
())
...
...
@@ -195,7 +199,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
emptyBodyWithCompletableFuture
()
throws
Exception
{
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
CompletableFuture
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
CompletableFuture
.
class
,
String
.
class
);
HttpEntity
<
CompletableFuture
<
String
>>
entity
=
resolveValueWithEmptyBody
(
type
);
entity
.
getBody
().
whenComplete
((
body
,
ex
)
->
{
...
...
@@ -217,7 +221,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
httpEntityWithMonoBody
()
throws
Exception
{
String
body
=
"line1"
;
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Mono
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Mono
.
class
,
String
.
class
);
HttpEntity
<
Mono
<
String
>>
httpEntity
=
resolveValue
(
type
,
body
);
assertEquals
(
this
.
request
.
getHeaders
(),
httpEntity
.
getHeaders
());
...
...
@@ -227,7 +231,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
httpEntityWithSingleBody
()
throws
Exception
{
String
body
=
"line1"
;
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Single
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Single
.
class
,
String
.
class
);
HttpEntity
<
Single
<
String
>>
httpEntity
=
resolveValue
(
type
,
body
);
assertEquals
(
this
.
request
.
getHeaders
(),
httpEntity
.
getHeaders
());
...
...
@@ -237,7 +241,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
httpEntityWithRxJava2SingleBody
()
throws
Exception
{
String
body
=
"line1"
;
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
io
.
reactivex
.
Single
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
io
.
reactivex
.
Single
.
class
,
String
.
class
);
HttpEntity
<
io
.
reactivex
.
Single
<
String
>>
httpEntity
=
resolveValue
(
type
,
body
);
assertEquals
(
this
.
request
.
getHeaders
(),
httpEntity
.
getHeaders
());
...
...
@@ -247,7 +251,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
httpEntityWithRxJava2MaybeBody
()
throws
Exception
{
String
body
=
"line1"
;
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Maybe
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Maybe
.
class
,
String
.
class
);
HttpEntity
<
Maybe
<
String
>>
httpEntity
=
resolveValue
(
type
,
body
);
assertEquals
(
this
.
request
.
getHeaders
(),
httpEntity
.
getHeaders
());
...
...
@@ -257,7 +261,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
httpEntityWithCompletableFutureBody
()
throws
Exception
{
String
body
=
"line1"
;
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
CompletableFuture
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
CompletableFuture
.
class
,
String
.
class
);
HttpEntity
<
CompletableFuture
<
String
>>
httpEntity
=
resolveValue
(
type
,
body
);
assertEquals
(
this
.
request
.
getHeaders
(),
httpEntity
.
getHeaders
());
...
...
@@ -267,7 +271,7 @@ public class HttpEntityArgumentResolverTests {
@Test
public
void
httpEntityWithFluxBody
()
throws
Exception
{
String
body
=
"line1\nline2\nline3\n"
;
ResolvableType
type
=
httpEntityType
(
forClassWithGenerics
(
Flux
.
class
,
String
.
class
)
);
ResolvableType
type
=
httpEntityType
(
Flux
.
class
,
String
.
class
);
HttpEntity
<
Flux
<
String
>>
httpEntity
=
resolveValue
(
type
,
body
);
assertEquals
(
this
.
request
.
getHeaders
(),
httpEntity
.
getHeaders
());
...
...
@@ -292,18 +296,13 @@ public class HttpEntityArgumentResolverTests {
}
private
ResolvableType
httpEntityType
(
Class
<?>
bodyType
)
{
return
httpEntityType
(
ResolvableType
.
forClass
(
bodyType
));
private
ResolvableType
httpEntityType
(
Class
<?>
bodyType
,
Class
<?>...
generics
)
{
return
ResolvableType
.
forClassWithGenerics
(
HttpEntity
.
class
,
ObjectUtils
.
isEmpty
(
generics
)
?
ResolvableType
.
forClass
(
bodyType
)
:
ResolvableType
.
forClassWithGenerics
(
bodyType
,
generics
));
}
private
ResolvableType
httpEntityType
(
ResolvableType
type
)
{
return
forClassWithGenerics
(
HttpEntity
.
class
,
type
);
}
private
void
testSupports
(
ResolvableType
type
)
{
MethodParameter
parameter
=
this
.
testMethod
.
arg
(
type
);
assertTrue
(
this
.
resolver
.
supportsParameter
(
parameter
));
}
@SuppressWarnings
(
"unchecked"
)
private
<
T
>
T
resolveValue
(
ResolvableType
type
,
String
body
)
{
...
...
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
浏览文件 @
a7582fcc
...
...
@@ -16,6 +16,7 @@
package
org.springframework.web.reactive.result.method.annotation
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -27,7 +28,6 @@ import rx.Single;
import
org.springframework.core.codec.ByteBufferEncoder
;
import
org.springframework.core.codec.CharSequenceEncoder
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.codec.EncoderHttpMessageWriter
;
import
org.springframework.http.codec.HttpMessageWriter
;
import
org.springframework.http.codec.ResourceHttpMessageWriter
;
...
...
@@ -41,7 +41,10 @@ import org.springframework.web.reactive.HandlerResult;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolver
;
import
org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder
;
import
static
org
.
junit
.
Assert
.*;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
springframework
.
web
.
method
.
ResolvableMethod
.
on
;
/**
* Unit tests for {@link ResponseBodyResultHandler}.When adding a test also
...
...
@@ -75,22 +78,42 @@ public class ResponseBodyResultHandlerTests {
@Test
public
void
supports
()
throws
NoSuchMethodException
{
Object
controller
=
new
TestController
();
testSupports
(
controller
,
"handleToString"
,
true
);
testSupports
(
controller
,
"doWork"
,
false
);
controller
=
new
TestRestController
();
testSupports
(
controller
,
"handleToString"
,
true
);
testSupports
(
controller
,
"handleToMonoString"
,
true
);
testSupports
(
controller
,
"handleToSingleString"
,
true
);
testSupports
(
controller
,
"handleToCompletable"
,
true
);
testSupports
(
controller
,
"handleToResponseEntity"
,
false
);
testSupports
(
controller
,
"handleToMonoResponseEntity"
,
false
);
Method
method
;
method
=
on
(
TestController
.
class
).
annotPresent
(
ResponseBody
.
class
).
resolveMethod
();
testSupports
(
controller
,
method
);
method
=
on
(
TestController
.
class
).
annotNotPresent
(
ResponseBody
.
class
).
resolveMethod
();
HandlerResult
handlerResult
=
getHandlerResult
(
controller
,
method
);
assertFalse
(
this
.
resultHandler
.
supports
(
handlerResult
));
}
@Test
public
void
supportsRestController
()
throws
NoSuchMethodException
{
Object
controller
=
new
TestRestController
();
Method
method
;
method
=
on
(
TestRestController
.
class
).
returning
(
String
.
class
).
resolveMethod
();
testSupports
(
controller
,
method
);
method
=
on
(
TestRestController
.
class
).
returning
(
Mono
.
class
,
String
.
class
).
resolveMethod
();
testSupports
(
controller
,
method
);
method
=
on
(
TestRestController
.
class
).
returning
(
Single
.
class
,
String
.
class
).
resolveMethod
();
testSupports
(
controller
,
method
);
method
=
on
(
TestRestController
.
class
).
returning
(
Completable
.
class
).
resolveMethod
();
testSupports
(
controller
,
method
);
}
private
void
testSupports
(
Object
controller
,
String
method
,
boolean
result
)
throws
NoSuchMethodException
{
HandlerMethod
hm
=
handlerMethod
(
controller
,
method
);
HandlerResult
handlerResult
=
new
HandlerResult
(
hm
,
null
,
hm
.
getReturnType
());
assertEquals
(
result
,
this
.
resultHandler
.
supports
(
handlerResult
));
private
void
testSupports
(
Object
controller
,
Method
method
)
{
HandlerResult
handlerResult
=
getHandlerResult
(
controller
,
method
);
assertTrue
(
this
.
resultHandler
.
supports
(
handlerResult
));
}
private
HandlerResult
getHandlerResult
(
Object
controller
,
Method
method
)
{
HandlerMethod
handlerMethod
=
new
HandlerMethod
(
controller
,
method
);
return
new
HandlerResult
(
handlerMethod
,
null
,
handlerMethod
.
getReturnType
());
}
@Test
...
...
@@ -99,10 +122,6 @@ public class ResponseBodyResultHandlerTests {
}
private
HandlerMethod
handlerMethod
(
Object
controller
,
String
method
)
throws
NoSuchMethodException
{
return
new
HandlerMethod
(
controller
,
controller
.
getClass
().
getMethod
(
method
));
}
@RestController
@SuppressWarnings
(
"unused"
)
...
...
@@ -125,14 +144,6 @@ public class ResponseBodyResultHandlerTests {
public
Completable
handleToCompletable
()
{
return
null
;
}
public
ResponseEntity
<
String
>
handleToResponseEntity
()
{
return
null
;
}
public
Mono
<
ResponseEntity
<
String
>>
handleToMonoResponseEntity
()
{
return
null
;
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录