Improved generics support in ResolvableMethod
This commit is contained in:
parent
c5351fdbef
commit
0296d003af
|
|
@ -38,18 +38,21 @@ import org.springframework.cglib.proxy.Callback;
|
|||
import org.springframework.cglib.proxy.Enhancer;
|
||||
import org.springframework.cglib.proxy.Factory;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.SynthesizingMethodParameter;
|
||||
import org.springframework.objenesis.ObjenesisException;
|
||||
import org.springframework.objenesis.SpringObjenesis;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Convenience class to resolve a method and its parameters based on hints.
|
||||
* Convenience class to resolve method parameters from hints.
|
||||
*
|
||||
* <h1>Background</h1>
|
||||
*
|
||||
|
|
@ -57,19 +60,15 @@ import org.springframework.util.ReflectionUtils;
|
|||
* "TestController" with a diverse range of method signatures representing
|
||||
* supported annotations and argument types. It becomes challenging to use
|
||||
* naming strategies to keep track of methods and arguments especially in
|
||||
* combination variables for reflection metadata.
|
||||
* combination with variables for reflection metadata.
|
||||
*
|
||||
* <p>The idea with {@link ResolvableMethod} is NOT to rely on naming techniques
|
||||
* but to use hints to zero in on method parameters. Especially in combination
|
||||
* with {@link ResolvableType} such hints can be strongly typed and make tests
|
||||
* more readable by being explicit about what is being tested and more robust
|
||||
* since the provided hints have to match.
|
||||
*
|
||||
* <p>Common use cases:
|
||||
* but to use hints to zero in on method parameters. Such hints can be strongly
|
||||
* typed and explicit about what is being tested.
|
||||
*
|
||||
* <h2>1. Declared Return Type</h2>
|
||||
*
|
||||
* When testing return types it's common to have many methods with a unique
|
||||
* When testing return types it's likely to have many methods with a unique
|
||||
* return type, possibly with or without an annotation.
|
||||
*
|
||||
* <pre>
|
||||
|
|
@ -78,6 +77,8 @@ import org.springframework.util.ReflectionUtils;
|
|||
*
|
||||
* // Return type
|
||||
* on(TestController.class).resolveReturnType(Foo.class);
|
||||
* on(TestController.class).resolveReturnType(List.class, Foo.class);
|
||||
* on(TestController.class).resolveReturnType(Mono.class, responseEntity(Foo.class));
|
||||
*
|
||||
* // Annotation + return type
|
||||
* on(TestController.class).annotated(ResponseBody.class).resolveReturnType(Bar.class);
|
||||
|
|
@ -85,7 +86,7 @@ import org.springframework.util.ReflectionUtils;
|
|||
* // Annotation not present
|
||||
* on(TestController.class).notAnnotated(ResponseBody.class).resolveReturnType();
|
||||
*
|
||||
* // Annotation properties
|
||||
* // Annotation with attributes
|
||||
* on(TestController.class)
|
||||
* .annotated(RequestMapping.class, patterns("/foo"), params("p"))
|
||||
* .annotated(ResponseBody.class)
|
||||
|
|
@ -124,6 +125,9 @@ public class ResolvableMethod {
|
|||
|
||||
private static final SpringObjenesis objenesis = new SpringObjenesis();
|
||||
|
||||
private static final ParameterNameDiscoverer nameDiscoverer =
|
||||
new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
|
||||
private final Method method;
|
||||
|
||||
|
|
@ -151,9 +155,20 @@ public class ResolvableMethod {
|
|||
/**
|
||||
* Find a unique argument matching the given type.
|
||||
* @param type the expected type
|
||||
* @param generics optional array of generic types
|
||||
*/
|
||||
public MethodParameter arg(Class<?> type) {
|
||||
return new ArgResolver().arg(type);
|
||||
public MethodParameter arg(Class<?> type, Class<?>... generics) {
|
||||
return new ArgResolver().arg(type, generics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a unique argument matching the given type.
|
||||
* @param type the expected type
|
||||
* @param generic at least one generic type
|
||||
* @param generics optional array of generic types
|
||||
*/
|
||||
public MethodParameter arg(Class<?> type, ResolvableType generic, ResolvableType... generics) {
|
||||
return new ArgResolver().arg(type, generic, generics);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -207,6 +222,19 @@ public class ResolvableMethod {
|
|||
.collect(Collectors.joining(",\n\t", "(\n\t", "\n)"));
|
||||
}
|
||||
|
||||
private static ResolvableType toResolvableType(Class<?> type, Class<?>... generics) {
|
||||
return ObjectUtils.isEmpty(generics) ?
|
||||
ResolvableType.forClass(type) :
|
||||
ResolvableType.forClassWithGenerics(type, generics);
|
||||
}
|
||||
|
||||
private static ResolvableType toResolvableType(Class<?> type, ResolvableType generic, ResolvableType... generics) {
|
||||
ResolvableType[] genericTypes = new ResolvableType[generics.length + 1];
|
||||
genericTypes[0] = generic;
|
||||
System.arraycopy(generics, 0, genericTypes, 1, generics.length);
|
||||
return ResolvableType.forClassWithGenerics(type, genericTypes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main entry point providing access to a {@code ResolvableMethod} builder.
|
||||
|
|
@ -278,16 +306,29 @@ public class ResolvableMethod {
|
|||
|
||||
/**
|
||||
* Filter on methods returning the given type.
|
||||
* @param returnType the return type
|
||||
* @param generics optional array of generic types
|
||||
*/
|
||||
public Builder returning(Class<?> returnType) {
|
||||
return returning(ResolvableType.forClass(returnType));
|
||||
public Builder returning(Class<?> returnType, Class<?>... generics) {
|
||||
return returning(toResolvableType(returnType, generics));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter on methods returning the given type with generics.
|
||||
* @param returnType the return type
|
||||
* @param generic at least one generic type
|
||||
* @param generics optional extra generic types
|
||||
*/
|
||||
public Builder returning(Class<?> returnType, ResolvableType generic, ResolvableType... generics) {
|
||||
return returning(toResolvableType(returnType, generic, generics));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter on methods returning the given type.
|
||||
* @param returnType the return type
|
||||
*/
|
||||
public Builder returning(ResolvableType resolvableType) {
|
||||
String expected = resolvableType.toString();
|
||||
public Builder returning(ResolvableType returnType) {
|
||||
String expected = returnType.toString();
|
||||
String message = "returnType=" + expected;
|
||||
addFilter(message, m -> expected.equals(ResolvableType.forMethodReturnType(m).toString()));
|
||||
return this;
|
||||
|
|
@ -336,7 +377,7 @@ public class ResolvableMethod {
|
|||
}
|
||||
|
||||
|
||||
// Build & Resolve shortcuts...
|
||||
// Build & resolve shortcuts...
|
||||
|
||||
/**
|
||||
* Resolve and return the {@code Method} equivalent to:
|
||||
|
|
@ -365,15 +406,26 @@ public class ResolvableMethod {
|
|||
/**
|
||||
* Shortcut to the unique return type equivalent to:
|
||||
* <p>{@code returning(returnType).build().returnType()}
|
||||
* @param returnType the return type
|
||||
* @param generics optional array of generic types
|
||||
*/
|
||||
public MethodParameter resolveReturnType(Class<?> returnType) {
|
||||
return returning(returnType).build().returnType();
|
||||
public MethodParameter resolveReturnType(Class<?> returnType, Class<?>... generics) {
|
||||
return returning(returnType, generics).build().returnType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to the unique return type equivalent to:
|
||||
* <p>{@code returning(returnType).build().returnType()}
|
||||
* @param returnType the return type
|
||||
* @param generic at least one generic type
|
||||
* @param generics optional extra generic types
|
||||
*/
|
||||
public MethodParameter resolveReturnType(Class<?> returnType, ResolvableType generic,
|
||||
ResolvableType... generics) {
|
||||
|
||||
return returning(returnType, generic, generics).build().returnType();
|
||||
}
|
||||
|
||||
public MethodParameter resolveReturnType(ResolvableType returnType) {
|
||||
return returning(returnType).build().returnType();
|
||||
}
|
||||
|
|
@ -392,51 +444,6 @@ public class ResolvableMethod {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T initProxy(Class<?> type, MethodInvocationInterceptor interceptor) {
|
||||
Assert.notNull(type, "'type' must not be null");
|
||||
if (type.isInterface()) {
|
||||
ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE);
|
||||
factory.addInterface(type);
|
||||
factory.addInterface(Supplier.class);
|
||||
factory.addAdvice(interceptor);
|
||||
return (T) factory.getProxy();
|
||||
}
|
||||
|
||||
else {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(type);
|
||||
enhancer.setInterfaces(new Class<?>[] {Supplier.class});
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
||||
|
||||
Class<?> proxyClass = enhancer.createClass();
|
||||
Object proxy = null;
|
||||
|
||||
if (objenesis.isWorthTrying()) {
|
||||
try {
|
||||
proxy = objenesis.newInstance(proxyClass, enhancer.getUseCache());
|
||||
}
|
||||
catch (ObjenesisException ex) {
|
||||
logger.debug("Objenesis failed, falling back to default constructor", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (proxy == null) {
|
||||
try {
|
||||
proxy = ReflectionUtils.accessibleConstructor(proxyClass).newInstance();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Unable to instantiate proxy " +
|
||||
"via both Objenesis and default constructor fails as well", ex);
|
||||
}
|
||||
}
|
||||
|
||||
((Factory) proxy).setCallbacks(new Callback[] {interceptor});
|
||||
return (T) proxy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicate with a descriptive label.
|
||||
*/
|
||||
|
|
@ -533,9 +540,16 @@ public class ResolvableMethod {
|
|||
* Resolve the argument also matching to the given type.
|
||||
* @param type the expected type
|
||||
*/
|
||||
public MethodParameter arg(Class<?> type) {
|
||||
this.filters.add(p -> type.equals(p.getParameterType()));
|
||||
return arg(ResolvableType.forClass(type));
|
||||
public MethodParameter arg(Class<?> type, Class<?>... generics) {
|
||||
return arg(toResolvableType(type, generics));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the argument also matching to the given type.
|
||||
* @param type the expected type
|
||||
*/
|
||||
public MethodParameter arg(Class<?> type, ResolvableType generic, ResolvableType... generics) {
|
||||
return arg(toResolvableType(type, generic, generics));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -562,6 +576,7 @@ public class ResolvableMethod {
|
|||
List<MethodParameter> matches = new ArrayList<>();
|
||||
for (int i = 0; i < method.getParameterCount(); i++) {
|
||||
MethodParameter param = new SynthesizingMethodParameter(method, i);
|
||||
param.initParameterNameDiscovery(nameDiscoverer);
|
||||
if (this.filters.stream().allMatch(p -> p.test(param))) {
|
||||
matches.add(param);
|
||||
}
|
||||
|
|
@ -597,4 +612,49 @@ public class ResolvableMethod {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T initProxy(Class<?> type, MethodInvocationInterceptor interceptor) {
|
||||
Assert.notNull(type, "'type' must not be null");
|
||||
if (type.isInterface()) {
|
||||
ProxyFactory factory = new ProxyFactory(EmptyTargetSource.INSTANCE);
|
||||
factory.addInterface(type);
|
||||
factory.addInterface(Supplier.class);
|
||||
factory.addAdvice(interceptor);
|
||||
return (T) factory.getProxy();
|
||||
}
|
||||
|
||||
else {
|
||||
Enhancer enhancer = new Enhancer();
|
||||
enhancer.setSuperclass(type);
|
||||
enhancer.setInterfaces(new Class<?>[] {Supplier.class});
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class);
|
||||
|
||||
Class<?> proxyClass = enhancer.createClass();
|
||||
Object proxy = null;
|
||||
|
||||
if (objenesis.isWorthTrying()) {
|
||||
try {
|
||||
proxy = objenesis.newInstance(proxyClass, enhancer.getUseCache());
|
||||
}
|
||||
catch (ObjenesisException ex) {
|
||||
logger.debug("Objenesis failed, falling back to default constructor", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (proxy == null) {
|
||||
try {
|
||||
proxy = ReflectionUtils.accessibleConstructor(proxyClass).newInstance();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Unable to instantiate proxy " +
|
||||
"via both Objenesis and default constructor fails as well", ex);
|
||||
}
|
||||
}
|
||||
|
||||
((Factory) proxy).setCallbacks(new Callback[] {interceptor});
|
||||
return (T) proxy;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
|
|
@ -59,7 +58,6 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
|
||||
/**
|
||||
* Test fixture with {@link org.springframework.web.method.annotation.RequestParamMethodArgumentResolver}.
|
||||
|
|
@ -101,7 +99,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(List.class, MultipartFile.class));
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(List.class, MultipartFile.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(MultipartFile[].class);
|
||||
|
|
@ -110,7 +108,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
param = this.testMethod.annotated(RequestParam.class).arg(Part.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(List.class, Part.class));
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(List.class, Part.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(Part[].class);
|
||||
|
|
@ -125,7 +123,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
param = this.testMethod.notAnnotated().arg(MultipartFile.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(RequestParam.class).arg(forClassWithGenerics(List.class, MultipartFile.class));
|
||||
param = this.testMethod.notAnnotated(RequestParam.class).arg(List.class, MultipartFile.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(RequestParam.class).arg(Part.class);
|
||||
|
|
@ -140,10 +138,10 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
param = this.testMethod.annotated(RequestParam.class, required().negate()).arg(String.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(Optional.class, Integer.class));
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(Optional.class, Integer.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(forClassWithGenerics(Optional.class, MultipartFile.class));
|
||||
param = this.testMethod.annotated(RequestParam.class).arg(Optional.class, MultipartFile.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
resolver = new RequestParamMethodArgumentResolver(null, false);
|
||||
|
|
@ -201,8 +199,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(List.class, MultipartFile.class));
|
||||
.annotated(RequestParam.class).arg(List.class, MultipartFile.class);
|
||||
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertTrue(result instanceof List);
|
||||
|
|
@ -255,10 +252,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
request.addPart(new MockPart("other", "Hello World 3".getBytes()));
|
||||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(List.class, Part.class));
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestParam.class).arg(List.class, Part.class);
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertTrue(result instanceof List);
|
||||
assertEquals(Arrays.asList(expected1, expected2), result);
|
||||
|
|
@ -293,8 +287,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod.notAnnotated().arg(MultipartFile.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertTrue(result instanceof MultipartFile);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
|
|
@ -310,9 +302,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.notAnnotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(List.class, MultipartFile.class));
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
.notAnnotated(RequestParam.class).arg(List.class, MultipartFile.class);
|
||||
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertTrue(result instanceof List);
|
||||
|
|
@ -335,9 +325,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.notAnnotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(List.class, MultipartFile.class));
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
.notAnnotated(RequestParam.class).arg(List.class, MultipartFile.class);
|
||||
|
||||
Object actual = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertTrue(actual instanceof List);
|
||||
|
|
@ -371,7 +359,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(Part.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertTrue(result instanceof Part);
|
||||
assertEquals("Invalid result", expected, result);
|
||||
|
|
@ -403,7 +390,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
this.request.addParameter("stringNotAnnot", "");
|
||||
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
Object arg = resolver.resolveArgument(param, null, webRequest, binderFactory);
|
||||
assertNull(arg);
|
||||
}
|
||||
|
|
@ -427,9 +413,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
public void resolveSimpleTypeParam() throws Exception {
|
||||
request.setParameter("stringNotAnnot", "plainValue");
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
|
||||
assertTrue(result instanceof String);
|
||||
assertEquals("plainValue", result);
|
||||
|
|
@ -438,7 +422,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
@Test // SPR-8561
|
||||
public void resolveSimpleTypeParamToNull() throws Exception {
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertNull(result);
|
||||
}
|
||||
|
|
@ -455,7 +438,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
public void resolveEmptyValueWithoutDefault() throws Exception {
|
||||
this.request.addParameter("stringNotAnnot", "");
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, null);
|
||||
assertEquals("", result);
|
||||
}
|
||||
|
|
@ -476,8 +458,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(Optional.class, Integer.class));
|
||||
.annotated(RequestParam.class).arg(Optional.class, Integer.class);
|
||||
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);
|
||||
assertEquals(Optional.empty(), result);
|
||||
|
|
@ -500,8 +481,7 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
webRequest = new ServletWebRequest(request);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(Optional.class, MultipartFile.class));
|
||||
.annotated(RequestParam.class).arg(Optional.class, MultipartFile.class);
|
||||
|
||||
Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);
|
||||
assertTrue(result instanceof Optional);
|
||||
|
|
@ -518,10 +498,10 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
request.setContentType("multipart/form-data");
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(Optional.class, MultipartFile.class));
|
||||
.annotated(RequestParam.class).arg(Optional.class, MultipartFile.class);
|
||||
|
||||
assertEquals(Optional.empty(), resolver.resolveArgument(param, null, webRequest, binderFactory));
|
||||
Object actual = resolver.resolveArgument(param, null, webRequest, binderFactory);
|
||||
assertEquals(Optional.empty(), actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -531,10 +511,10 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);
|
||||
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestParam.class)
|
||||
.arg(forClassWithGenerics(Optional.class, MultipartFile.class));
|
||||
.annotated(RequestParam.class).arg(Optional.class, MultipartFile.class);
|
||||
|
||||
assertEquals(Optional.empty(), resolver.resolveArgument(param, null, webRequest, binderFactory));
|
||||
Object actual = resolver.resolveArgument(param, null, webRequest, binderFactory);
|
||||
assertEquals(Optional.empty(), actual);
|
||||
}
|
||||
|
||||
private Predicate<RequestParam> name(String name) {
|
||||
|
|
|
|||
|
|
@ -59,11 +59,10 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
|
||||
import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
|
||||
import static org.springframework.web.method.ResolvableMethod.on;
|
||||
import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AbstractMessageWriterResultHandler}.
|
||||
|
|
@ -110,27 +109,19 @@ public class MessageWriterResultHandlerTests {
|
|||
@Test
|
||||
public void voidReturnType() throws Exception {
|
||||
testVoid(null, on(TestController.class).resolveReturnType(void.class));
|
||||
testVoid(Mono.empty(), on(TestController.class).resolveReturnType(Mono.class, Void.class));
|
||||
testVoid(Flux.empty(), on(TestController.class).resolveReturnType(Flux.class, Void.class));
|
||||
testVoid(Completable.complete(), on(TestController.class).resolveReturnType(Completable.class));
|
||||
testVoid(Observable.empty(), on(TestController.class).resolveReturnType(Observable.class, Void.class));
|
||||
|
||||
testVoid(Mono.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(Mono.class, Void.class)));
|
||||
MethodParameter type = on(TestController.class).resolveReturnType(io.reactivex.Completable.class);
|
||||
testVoid(io.reactivex.Completable.complete(), type);
|
||||
|
||||
testVoid(Flux.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(Flux.class, Void.class)));
|
||||
type = on(TestController.class).resolveReturnType(io.reactivex.Observable.class, Void.class);
|
||||
testVoid(io.reactivex.Observable.empty(), type);
|
||||
|
||||
testVoid(Completable.complete(), on(TestController.class)
|
||||
.resolveReturnType(Completable.class));
|
||||
|
||||
testVoid(Observable.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(Observable.class, Void.class)));
|
||||
|
||||
testVoid(io.reactivex.Completable.complete(), on(TestController.class)
|
||||
.resolveReturnType(io.reactivex.Completable.class));
|
||||
|
||||
testVoid(io.reactivex.Observable.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(io.reactivex.Observable.class, Void.class)));
|
||||
|
||||
testVoid(Flowable.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(Flowable.class, Void.class)));
|
||||
type = on(TestController.class).resolveReturnType(Flowable.class, Void.class);
|
||||
testVoid(Flowable.empty(), type);
|
||||
}
|
||||
|
||||
private void testVoid(Object body, MethodParameter returnType) {
|
||||
|
|
@ -155,9 +146,7 @@ public class MessageWriterResultHandlerTests {
|
|||
@Test // SPR-12811
|
||||
public void jacksonTypeOfListElement() throws Exception {
|
||||
|
||||
MethodParameter returnType = on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(List.class, ParentClass.class));
|
||||
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(List.class, ParentClass.class);
|
||||
List<ParentClass> body = Arrays.asList(new Foo("foo"), new Bar("bar"));
|
||||
this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5));
|
||||
|
||||
|
|
@ -179,8 +168,7 @@ public class MessageWriterResultHandlerTests {
|
|||
@Test // SPR-13318
|
||||
public void jacksonTypeWithSubTypeOfListElement() throws Exception {
|
||||
|
||||
MethodParameter returnType = on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(List.class, Identifiable.class));
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(List.class, Identifiable.class);
|
||||
|
||||
List<SimpleBean> body = Arrays.asList(new SimpleBean(123L, "foo"), new SimpleBean(456L, "bar"));
|
||||
this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5));
|
||||
|
|
|
|||
|
|
@ -38,13 +38,16 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
|||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.bind.support.WebExchangeBindException;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.method.ResolvableMethod;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.core.ResolvableType.*;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ModelAttributeMethodArgumentResolver}.
|
||||
|
|
@ -76,13 +79,13 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
MethodParameter param = this.testMethod.annotated(ModelAttribute.class).arg(Foo.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.annotated(ModelAttribute.class).arg(forClassWithGenerics(Mono.class, Foo.class));
|
||||
param = this.testMethod.annotated(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(Foo.class);
|
||||
assertFalse(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(forClassWithGenerics(Mono.class, Foo.class));
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
assertFalse(resolver.supportsParameter(param));
|
||||
}
|
||||
|
||||
|
|
@ -94,13 +97,13 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
MethodParameter param = this.testMethod.notAnnotated(ModelAttribute.class).arg(Foo.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(forClassWithGenerics(Mono.class, Foo.class));
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
assertTrue(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(String.class);
|
||||
assertFalse(resolver.supportsParameter(param));
|
||||
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(forClassWithGenerics(Mono.class, String.class));
|
||||
param = this.testMethod.notAnnotated(ModelAttribute.class).arg(Mono.class, String.class);
|
||||
assertFalse(resolver.supportsParameter(param));
|
||||
}
|
||||
|
||||
|
|
@ -115,8 +118,8 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
@Test
|
||||
public void createAndBindToMono() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod.notAnnotated(ModelAttribute.class)
|
||||
.arg(forClassWithGenerics(Mono.class, Foo.class));
|
||||
MethodParameter parameter = this.testMethod
|
||||
.notAnnotated(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
|
||||
testBindFoo(parameter, mono -> {
|
||||
assertTrue(mono.getClass().getName(), mono instanceof Mono);
|
||||
|
|
@ -129,8 +132,8 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
@Test
|
||||
public void createAndBindToSingle() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod.annotated(ModelAttribute.class)
|
||||
.arg(forClassWithGenerics(Single.class, Foo.class));
|
||||
MethodParameter parameter = this.testMethod
|
||||
.annotated(ModelAttribute.class).arg(Single.class, Foo.class);
|
||||
|
||||
testBindFoo(parameter, single -> {
|
||||
assertTrue(single.getClass().getName(), single instanceof Single);
|
||||
|
|
@ -191,8 +194,8 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
foo.setName("Jim");
|
||||
this.bindContext.getModel().addAttribute("foo", Mono.just(foo));
|
||||
|
||||
MethodParameter parameter = this.testMethod.notAnnotated(ModelAttribute.class)
|
||||
.arg(forClassWithGenerics(Mono.class, Foo.class));
|
||||
MethodParameter parameter = this.testMethod
|
||||
.notAnnotated(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
|
||||
testBindFoo(parameter, mono -> {
|
||||
assertTrue(mono.getClass().getName(), mono instanceof Mono);
|
||||
|
|
@ -230,8 +233,8 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void validationErrorToMono() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod.notAnnotated(ModelAttribute.class)
|
||||
.arg(forClassWithGenerics(Mono.class, Foo.class));
|
||||
MethodParameter parameter = this.testMethod
|
||||
.notAnnotated(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
|
||||
testValidationError(parameter,
|
||||
resolvedArgumentMono -> {
|
||||
|
|
@ -246,8 +249,8 @@ public class ModelAttributeMethodArgumentResolverTests {
|
|||
@SuppressWarnings("unchecked")
|
||||
public void validationErrorToSingle() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod.annotated(ModelAttribute.class)
|
||||
.arg(forClassWithGenerics(Single.class, Foo.class));
|
||||
MethodParameter parameter = this.testMethod
|
||||
.annotated(ModelAttribute.class).arg(Single.class, Foo.class);
|
||||
|
||||
testValidationError(parameter,
|
||||
resolvedArgumentMono -> {
|
||||
|
|
|
|||
|
|
@ -33,15 +33,14 @@ import rx.RxReactiveStreams;
|
|||
import rx.Single;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
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.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.method.ResolvableMethod;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
|
|
@ -51,7 +50,6 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RequestBodyArgumentResolver}. When adding a test also
|
||||
|
|
@ -77,13 +75,13 @@ public class RequestBodyArgumentResolverTests {
|
|||
|
||||
@Test
|
||||
public void supports() throws Exception {
|
||||
MethodParameter param;
|
||||
|
||||
ResolvableType type = forClassWithGenerics(Mono.class, String.class);
|
||||
assertTrue(this.resolver.supportsParameter(
|
||||
this.testMethod.annotated(RequestBody.class, required()).arg(type)));
|
||||
param = this.testMethod.annotated(RequestBody.class, required()).arg(Mono.class, String.class);
|
||||
assertTrue(this.resolver.supportsParameter(param));
|
||||
|
||||
MethodParameter parameter = this.testMethod.notAnnotated(RequestBody.class).arg(String.class);
|
||||
assertFalse(this.resolver.supportsParameter(parameter));
|
||||
param = this.testMethod.notAnnotated(RequestBody.class).arg(String.class);
|
||||
assertFalse(this.resolver.supportsParameter(param));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -112,15 +110,15 @@ public class RequestBodyArgumentResolverTests {
|
|||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void emptyBodyWithMono() throws Exception {
|
||||
ResolvableType type = forClassWithGenerics(Mono.class, String.class);
|
||||
MethodParameter param;
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestBody.class, required()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, required()).arg(Mono.class, String.class);
|
||||
StepVerifier.create((Mono<Void>) resolveValueWithEmptyBody(param))
|
||||
.expectNextCount(0)
|
||||
.expectError(ServerWebInputException.class)
|
||||
.verify();
|
||||
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(Mono.class, String.class);
|
||||
StepVerifier.create((Mono<Void>) resolveValueWithEmptyBody(param))
|
||||
.expectNextCount(0)
|
||||
.expectComplete()
|
||||
|
|
@ -130,15 +128,15 @@ public class RequestBodyArgumentResolverTests {
|
|||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void emptyBodyWithFlux() throws Exception {
|
||||
ResolvableType type = forClassWithGenerics(Flux.class, String.class);
|
||||
MethodParameter param;
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestBody.class, required()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, required()).arg(Flux.class, String.class);
|
||||
StepVerifier.create((Flux<Void>) resolveValueWithEmptyBody(param))
|
||||
.expectNextCount(0)
|
||||
.expectError(ServerWebInputException.class)
|
||||
.verify();
|
||||
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(Flux.class, String.class);
|
||||
StepVerifier.create((Flux<Void>) resolveValueWithEmptyBody(param))
|
||||
.expectNextCount(0)
|
||||
.expectComplete()
|
||||
|
|
@ -147,16 +145,16 @@ public class RequestBodyArgumentResolverTests {
|
|||
|
||||
@Test
|
||||
public void emptyBodyWithSingle() throws Exception {
|
||||
ResolvableType type = forClassWithGenerics(Single.class, String.class);
|
||||
MethodParameter param;
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestBody.class, required()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, required()).arg(Single.class, String.class);
|
||||
Single<String> single = resolveValueWithEmptyBody(param);
|
||||
StepVerifier.create(RxReactiveStreams.toPublisher(single))
|
||||
.expectNextCount(0)
|
||||
.expectError(ServerWebInputException.class)
|
||||
.verify();
|
||||
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(Single.class, String.class);
|
||||
single = resolveValueWithEmptyBody(param);
|
||||
StepVerifier.create(RxReactiveStreams.toPublisher(single))
|
||||
.expectNextCount(0)
|
||||
|
|
@ -166,16 +164,16 @@ public class RequestBodyArgumentResolverTests {
|
|||
|
||||
@Test
|
||||
public void emptyBodyWithMaybe() throws Exception {
|
||||
ResolvableType type = forClassWithGenerics(Maybe.class, String.class);
|
||||
MethodParameter param;
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestBody.class, required()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, required()).arg(Maybe.class, String.class);
|
||||
Maybe<String> maybe = resolveValueWithEmptyBody(param);
|
||||
StepVerifier.create(maybe.toFlowable())
|
||||
.expectNextCount(0)
|
||||
.expectError(ServerWebInputException.class)
|
||||
.verify();
|
||||
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(type);
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(Maybe.class, String.class);
|
||||
maybe = resolveValueWithEmptyBody(param);
|
||||
StepVerifier.create(maybe.toFlowable())
|
||||
.expectNextCount(0)
|
||||
|
|
@ -185,16 +183,19 @@ public class RequestBodyArgumentResolverTests {
|
|||
|
||||
@Test
|
||||
public void emptyBodyWithObservable() throws Exception {
|
||||
ResolvableType type = forClassWithGenerics(Observable.class, String.class);
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestBody.class, required()).arg(type);
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestBody.class, required()).arg(Observable.class, String.class);
|
||||
|
||||
Observable<String> observable = resolveValueWithEmptyBody(param);
|
||||
StepVerifier.create(RxReactiveStreams.toPublisher(observable))
|
||||
.expectNextCount(0)
|
||||
.expectError(ServerWebInputException.class)
|
||||
.verify();
|
||||
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(type);
|
||||
param = this.testMethod
|
||||
.annotated(RequestBody.class, notRequired()).arg(Observable.class, String.class);
|
||||
|
||||
observable = resolveValueWithEmptyBody(param);
|
||||
StepVerifier.create(RxReactiveStreams.toPublisher(observable))
|
||||
.expectNextCount(0)
|
||||
|
|
@ -204,16 +205,19 @@ public class RequestBodyArgumentResolverTests {
|
|||
|
||||
@Test
|
||||
public void emptyBodyWithCompletableFuture() throws Exception {
|
||||
ResolvableType type = forClassWithGenerics(CompletableFuture.class, String.class);
|
||||
|
||||
MethodParameter param = this.testMethod.annotated(RequestBody.class, required()).arg(type);
|
||||
MethodParameter param = this.testMethod
|
||||
.annotated(RequestBody.class, required()).arg(CompletableFuture.class, String.class);
|
||||
|
||||
CompletableFuture<String> future = resolveValueWithEmptyBody(param);
|
||||
future.whenComplete((text, ex) -> {
|
||||
assertNull(text);
|
||||
assertNotNull(ex);
|
||||
});
|
||||
|
||||
param = this.testMethod.annotated(RequestBody.class, notRequired()).arg(type);
|
||||
param = this.testMethod
|
||||
.annotated(RequestBody.class, notRequired()).arg(CompletableFuture.class, String.class);
|
||||
|
||||
future = resolveValueWithEmptyBody(param);
|
||||
future.whenComplete((text, ex) -> {
|
||||
assertNotNull(text);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import org.junit.Test;
|
|||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.http.MediaType;
|
||||
|
|
@ -145,7 +144,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
public void resolveSimpleTypeParam() throws Exception {
|
||||
ServerWebExchange exchange = exchangeWithQuery("stringNotAnnot=plainValue");
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
Object result = resolve(param, exchange);
|
||||
assertEquals("plainValue", result);
|
||||
}
|
||||
|
|
@ -153,7 +151,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
@Test // SPR-8561
|
||||
public void resolveSimpleTypeParamToNull() throws Exception {
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
assertNull(resolve(param, exchange()));
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +165,6 @@ public class RequestParamMethodArgumentResolverTests {
|
|||
@Test
|
||||
public void resolveEmptyValueWithoutDefault() throws Exception {
|
||||
MethodParameter param = this.testMethod.notAnnotated(RequestParam.class).arg(String.class);
|
||||
param.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
|
||||
assertEquals("", resolve(param, exchangeWithQuery("stringNotAnnot=")));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.core.ResolvableType.forClass;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
import static org.springframework.http.ResponseEntity.notFound;
|
||||
import static org.springframework.http.ResponseEntity.ok;
|
||||
|
|
@ -124,13 +123,13 @@ public class ResponseEntityResultHandlerTests {
|
|||
MethodParameter returnType = on(TestController.class).resolveReturnType(entity(String.class));
|
||||
assertTrue(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(asyncEntity(Mono.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Mono.class, entity(String.class));
|
||||
assertTrue(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(asyncEntity(Single.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Single.class, entity(String.class));
|
||||
assertTrue(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(asyncEntity(CompletableFuture.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(CompletableFuture.class, entity(String.class));
|
||||
assertTrue(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
}
|
||||
|
||||
|
|
@ -140,10 +139,10 @@ public class ResponseEntityResultHandlerTests {
|
|||
|
||||
Object value = null;
|
||||
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(forClass(String.class));
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(String.class);
|
||||
assertFalse(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClass(Completable.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Completable.class);
|
||||
assertFalse(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +180,7 @@ public class ResponseEntityResultHandlerTests {
|
|||
@Test
|
||||
public void handleResponseEntityWithNullBody() throws Exception {
|
||||
Object returnValue = Mono.just(notFound().build());
|
||||
MethodParameter type = on(TestController.class).resolveReturnType(asyncEntity(Mono.class, String.class));
|
||||
MethodParameter type = on(TestController.class).resolveReturnType(Mono.class, entity(String.class));
|
||||
HandlerResult result = handlerResult(returnValue, type);
|
||||
this.resultHandler.handleResult(createExchange(), result).block(Duration.ofSeconds(5));
|
||||
|
||||
|
|
@ -196,15 +195,15 @@ public class ResponseEntityResultHandlerTests {
|
|||
testHandle(returnValue, returnType);
|
||||
|
||||
returnValue = Mono.just(ok("abc"));
|
||||
returnType = on(TestController.class).resolveReturnType(asyncEntity(Mono.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Mono.class, entity(String.class));
|
||||
testHandle(returnValue, returnType);
|
||||
|
||||
returnValue = Mono.just(ok("abc"));
|
||||
returnType = on(TestController.class).resolveReturnType(asyncEntity(Single.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Single.class, entity(String.class));
|
||||
testHandle(returnValue, returnType);
|
||||
|
||||
returnValue = Mono.just(ok("abc"));
|
||||
returnType = on(TestController.class).resolveReturnType(asyncEntity(CompletableFuture.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(CompletableFuture.class, entity(String.class));
|
||||
testHandle(returnValue, returnType);
|
||||
}
|
||||
|
||||
|
|
@ -296,8 +295,8 @@ public class ResponseEntityResultHandlerTests {
|
|||
exchange.getAttributes().put(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE,
|
||||
Collections.singleton(MediaType.APPLICATION_JSON));
|
||||
|
||||
HandlerResult result = new HandlerResult(new TestController(), Mono.just(ok().body("body")),
|
||||
on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, ResponseEntity.class)));
|
||||
MethodParameter type = on(TestController.class).resolveReturnType(Mono.class, ResponseEntity.class);
|
||||
HandlerResult result = new HandlerResult(new TestController(), Mono.just(ok().body("body")), type);
|
||||
|
||||
this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));
|
||||
|
||||
|
|
@ -312,8 +311,7 @@ public class ResponseEntityResultHandlerTests {
|
|||
exchange.getAttributes().put(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE,
|
||||
Collections.singleton(MediaType.APPLICATION_JSON));
|
||||
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, ResponseEntity.class));
|
||||
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(Mono.class, ResponseEntity.class);
|
||||
HandlerResult result = new HandlerResult(new TestController(), Mono.just(notFound().build()), returnType);
|
||||
|
||||
this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));
|
||||
|
|
@ -339,11 +337,7 @@ public class ResponseEntityResultHandlerTests {
|
|||
}
|
||||
|
||||
private ResolvableType entity(Class<?> bodyType) {
|
||||
return forClassWithGenerics(ResponseEntity.class, forClass(bodyType));
|
||||
}
|
||||
|
||||
private ResolvableType asyncEntity(Class<?> asyncType, Class<?> bodyType) {
|
||||
return forClassWithGenerics(asyncType, entity(bodyType));
|
||||
return forClassWithGenerics(ResponseEntity.class, bodyType);
|
||||
}
|
||||
|
||||
private HandlerResult handlerResult(Object returnValue, MethodParameter returnType) {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.core.ResolvableType.forClass;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON;
|
||||
import static org.springframework.web.method.ResolvableMethod.on;
|
||||
|
||||
|
|
@ -90,11 +89,11 @@ public class ViewResolutionResultHandlerTests {
|
|||
|
||||
testSupports(on(TestController.class).resolveReturnType(String.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(View.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, String.class)));
|
||||
testSupports(on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, View.class)));
|
||||
testSupports(on(TestController.class).resolveReturnType(forClassWithGenerics(Single.class, String.class)));
|
||||
testSupports(on(TestController.class).resolveReturnType(forClassWithGenerics(Single.class, View.class)));
|
||||
testSupports(on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, Void.class)));
|
||||
testSupports(on(TestController.class).resolveReturnType(Mono.class, String.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Mono.class, View.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Single.class, String.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Single.class, View.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Mono.class, Void.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Completable.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Model.class));
|
||||
testSupports(on(TestController.class).resolveReturnType(Map.class));
|
||||
|
|
@ -139,27 +138,27 @@ public class ViewResolutionResultHandlerTests {
|
|||
returnValue = new TestView("account");
|
||||
testHandle("/path", returnType, returnValue, "account: {id=123}");
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, View.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Mono.class, View.class);
|
||||
returnValue = Mono.just(new TestView("account"));
|
||||
testHandle("/path", returnType, returnValue, "account: {id=123}");
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClass(String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(String.class);
|
||||
returnValue = "account";
|
||||
testHandle("/path", returnType, returnValue, "account: {id=123}", resolver);
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClassWithGenerics(Mono.class, String.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Mono.class, String.class);
|
||||
returnValue = Mono.just("account");
|
||||
testHandle("/path", returnType, returnValue, "account: {id=123}", resolver);
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClass(Model.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Model.class);
|
||||
returnValue = new ConcurrentModel().addAttribute("name", "Joe");
|
||||
testHandle("/account", returnType, returnValue, "account: {id=123, name=Joe}", resolver);
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClass(Map.class));
|
||||
returnType = on(TestController.class).resolveReturnType(Map.class);
|
||||
returnValue = Collections.singletonMap("name", "Joe");
|
||||
testHandle("/account", returnType, returnValue, "account: {id=123, name=Joe}", resolver);
|
||||
|
||||
returnType = on(TestController.class).resolveReturnType(forClass(TestBean.class));
|
||||
returnType = on(TestController.class).resolveReturnType(TestBean.class);
|
||||
returnValue = new TestBean("Joe");
|
||||
String responseBody = "account: {" +
|
||||
"id=123, " +
|
||||
|
|
@ -184,17 +183,10 @@ public class ViewResolutionResultHandlerTests {
|
|||
|
||||
@Test
|
||||
public void defaultViewName() throws Exception {
|
||||
|
||||
testDefaultViewName(null, on(TestController.class).resolveReturnType(String.class));
|
||||
|
||||
testDefaultViewName(Mono.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(Mono.class, String.class)));
|
||||
|
||||
testDefaultViewName(Mono.empty(), on(TestController.class)
|
||||
.resolveReturnType(forClassWithGenerics(Mono.class, Void.class)));
|
||||
|
||||
testDefaultViewName(Completable.complete(), on(TestController.class)
|
||||
.resolveReturnType(forClass(Completable.class)));
|
||||
testDefaultViewName(Mono.empty(), on(TestController.class).resolveReturnType(Mono.class, String.class));
|
||||
testDefaultViewName(Mono.empty(), on(TestController.class).resolveReturnType(Mono.class, Void.class));
|
||||
testDefaultViewName(Completable.complete(), on(TestController.class).resolveReturnType(Completable.class));
|
||||
}
|
||||
|
||||
private void testDefaultViewName(Object returnValue, MethodParameter returnType) throws URISyntaxException {
|
||||
|
|
|
|||
Loading…
Reference in New Issue