Browse Source

Increase sharing among InvocableHandlerMethod variants

In particular between reactive and non-reactive web variants, but
also preparing for a messaing reactive variant.
pull/2005/head
Rossen Stoyanchev 6 years ago
parent
commit
3f42e16172
  1. 57
      spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java
  2. 53
      spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java
  3. 56
      spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
  4. 53
      spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java
  5. 53
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java

57
spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java

@ -18,6 +18,8 @@ package org.springframework.messaging.handler; @@ -18,6 +18,8 @@ package org.springframework.messaging.handler;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -31,6 +33,8 @@ import org.springframework.core.annotation.SynthesizingMethodParameter; @@ -31,6 +33,8 @@ import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Encapsulates information about a handler method consisting of a
@ -321,6 +325,59 @@ public class HandlerMethod { @@ -321,6 +325,59 @@ public class HandlerMethod {
}
// Support methods for use in "InvocableHandlerMethod" sub-class variants..
@Nullable
protected static Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
if (!ObjectUtils.isEmpty(providedArgs)) {
for (Object providedArg : providedArgs) {
if (parameter.getParameterType().isInstance(providedArg)) {
return providedArg;
}
}
}
return null;
}
protected static String formatArgumentError(MethodParameter param, String message) {
return "Could not resolve parameter [" + param.getParameterIndex() + "] in " +
param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
}
/**
* Assert that the target bean class is an instance of the class where the given
* method is declared. In some cases the actual endpoint instance at request-
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
* beans, and others). Endpoint classes that require proxying should prefer
* class-based proxy mechanisms.
*/
protected void assertTargetBean(Method method, Object targetBean, Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
Class<?> targetBeanClass = targetBean.getClass();
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
"' is not an instance of the actual endpoint bean class '" +
targetBeanClass.getName() + "'. If the endpoint requires proxying " +
"(e.g. due to @Transactional), please use class-based proxying.";
throw new IllegalStateException(formatInvokeError(text, args));
}
}
protected String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Endpoint [" + getBeanType().getName() + "]\n" +
"Method [" + getBridgedMethod().toGenericString() + "] " +
"with argument values:\n" + formattedArgs;
}
/**
* A MethodParameter with HandlerMethod-specific behavior.
*/

53
spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java

@ -20,8 +20,6 @@ import java.lang.reflect.InvocationTargetException; @@ -20,8 +20,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
@ -32,7 +30,6 @@ import org.springframework.messaging.Message; @@ -32,7 +30,6 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.handler.HandlerMethod;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Extension of {@link HandlerMethod} that invokes the underlying method with
@ -163,23 +160,6 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -163,23 +160,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
return args;
}
@Nullable
private Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
if (!ObjectUtils.isEmpty(providedArgs)) {
for (Object providedArg : providedArgs) {
if (parameter.getParameterType().isInstance(providedArg)) {
return providedArg;
}
}
}
return null;
}
private static String formatArgumentError(MethodParameter param, String message) {
return "Could not resolve parameter [" + param.getParameterIndex() + "] in " +
param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
}
/**
* Invoke the handler method with the given argument values.
*/
@ -212,39 +192,6 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -212,39 +192,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
}
/**
* Assert that the target bean class is an instance of the class where the given
* method is declared. In some cases the actual endpoint instance at request-
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
* beans, and others). Endpoint classes that require proxying should prefer
* class-based proxy mechanisms.
*/
private void assertTargetBean(Method method, Object targetBean, Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
Class<?> targetBeanClass = targetBean.getClass();
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
"' is not an instance of the actual endpoint bean class '" +
targetBeanClass.getName() + "'. If the endpoint requires proxying " +
"(e.g. due to @Transactional), please use class-based proxying.";
throw new IllegalStateException(formatInvokeError(text, args));
}
}
private String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Endpoint [" + getBeanType().getName() + "]\n" +
"Method [" + getBridgedMethod().toGenericString() + "] " +
"with argument values:\n" + formattedArgs;
}
MethodParameter getAsyncReturnValueType(@Nullable Object returnValue) {
return new AsyncResultMethodParameter(returnValue);
}

56
spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java

@ -21,6 +21,8 @@ import java.lang.reflect.Method; @@ -21,6 +21,8 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -36,6 +38,8 @@ import org.springframework.http.HttpStatus; @@ -36,6 +38,8 @@ import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
@ -172,7 +176,6 @@ public class HandlerMethod { @@ -172,7 +176,6 @@ public class HandlerMethod {
this.resolvedFromHandlerMethod = handlerMethod;
}
private MethodParameter[] initMethodParameters() {
int count = this.bridgedMethod.getParameterCount();
MethodParameter[] result = new MethodParameter[count];
@ -390,6 +393,57 @@ public class HandlerMethod { @@ -390,6 +393,57 @@ public class HandlerMethod {
}
// Support methods for use in "InvocableHandlerMethod" sub-class variants..
@Nullable
protected static Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
if (!ObjectUtils.isEmpty(providedArgs)) {
for (Object providedArg : providedArgs) {
if (parameter.getParameterType().isInstance(providedArg)) {
return providedArg;
}
}
}
return null;
}
protected static String formatArgumentError(MethodParameter param, String message) {
return "Could not resolve parameter [" + param.getParameterIndex() + "] in " +
param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
}
/**
* Assert that the target bean class is an instance of the class where the given
* method is declared. In some cases the actual controller instance at request-
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
* beans, and others). {@code @Controller}'s that require proxying should prefer
* class-based proxy mechanisms.
*/
protected void assertTargetBean(Method method, Object targetBean, Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
Class<?> targetBeanClass = targetBean.getClass();
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
"' is not an instance of the actual controller bean class '" +
targetBeanClass.getName() + "'. If the controller requires proxying " +
"(e.g. due to @Transactional), please use class-based proxying.";
throw new IllegalStateException(formatInvokeError(text, args));
}
}
protected String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Controller [" + getBeanType().getName() + "]\n" +
"Method [" + getBridgedMethod().toGenericString() + "] " +
"with argument values:\n" + formattedArgs;
}
/**
* A MethodParameter with HandlerMethod-specific behavior.
*/

53
spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java

@ -19,8 +19,6 @@ package org.springframework.web.method.support; @@ -19,8 +19,6 @@ package org.springframework.web.method.support;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
@ -28,7 +26,6 @@ import org.springframework.core.ParameterNameDiscoverer; @@ -28,7 +26,6 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.support.WebDataBinderFactory;
@ -182,23 +179,6 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -182,23 +179,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
return args;
}
@Nullable
private Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
if (!ObjectUtils.isEmpty(providedArgs)) {
for (Object providedArg : providedArgs) {
if (parameter.getParameterType().isInstance(providedArg)) {
return providedArg;
}
}
}
return null;
}
private static String formatArgumentError(MethodParameter param, String message) {
return "Could not resolve parameter [" + param.getParameterIndex() + "] in " +
param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
}
/**
* Invoke the handler method with the given argument values.
*/
@ -231,37 +211,4 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -231,37 +211,4 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
}
/**
* Assert that the target bean class is an instance of the class where the given
* method is declared. In some cases the actual controller instance at request-
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
* beans, and others). {@code @Controller}'s that require proxying should prefer
* class-based proxy mechanisms.
*/
private void assertTargetBean(Method method, Object targetBean, Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
Class<?> targetBeanClass = targetBean.getClass();
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
"' is not an instance of the actual controller bean class '" +
targetBeanClass.getName() + "'. If the controller requires proxying " +
"(e.g. due to @Transactional), please use class-based proxying.";
throw new IllegalStateException(formatInvokeError(text, args));
}
}
private String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Controller [" + getBeanType().getName() + "]\n" +
"Method [" + getBridgedMethod().toGenericString() + "] " +
"with argument values:\n" + formattedArgs;
}
}

53
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java

@ -22,8 +22,6 @@ import java.lang.reflect.ParameterizedType; @@ -22,8 +22,6 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import reactor.core.publisher.Mono;
@ -38,7 +36,6 @@ import org.springframework.http.server.reactive.ServerHttpResponse; @@ -38,7 +36,6 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerResult;
@ -204,23 +201,6 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -204,23 +201,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
Stream.of(values).map(o -> o != NO_ARG_VALUE ? o : null).toArray());
}
@Nullable
private Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
if (!ObjectUtils.isEmpty(providedArgs)) {
for (Object providedArg : providedArgs) {
if (parameter.getParameterType().isInstance(providedArg)) {
return providedArg;
}
}
}
return null;
}
private static String formatArgumentError(MethodParameter param, String message) {
return "Could not resolve parameter [" + param.getParameterIndex() + "] in " +
param.getExecutable().toGenericString() + (StringUtils.hasText(message) ? ": " + message : "");
}
private void logArgumentErrorIfNecessary(
ServerWebExchange exchange, MethodParameter parameter, Throwable cause) {
@ -233,39 +213,6 @@ public class InvocableHandlerMethod extends HandlerMethod { @@ -233,39 +213,6 @@ public class InvocableHandlerMethod extends HandlerMethod {
}
}
/**
* Assert that the target bean class is an instance of the class where the given
* method is declared. In some cases the actual controller instance at request-
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
* beans, and others). {@code @Controller}'s that require proxying should prefer
* class-based proxy mechanisms.
*/
private void assertTargetBean(Method method, Object targetBean, Object[] args) {
Class<?> methodDeclaringClass = method.getDeclaringClass();
Class<?> targetBeanClass = targetBean.getClass();
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
"' is not an instance of the actual controller bean class '" +
targetBeanClass.getName() + "'. If the controller requires proxying " +
"(e.g. due to @Transactional), please use class-based proxying.";
throw new IllegalStateException(formatInvokeError(text, args));
}
}
private String formatInvokeError(String text, Object[] args) {
String formattedArgs = IntStream.range(0, args.length)
.mapToObj(i -> (args[i] != null ?
"[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" :
"[" + i + "] [null]"))
.collect(Collectors.joining(",\n", " ", " "));
return text + "\n" +
"Controller [" + getBeanType().getName() + "]\n" +
"Method [" + getBridgedMethod().toGenericString() + "]\n" +
"with argument values:\n" + formattedArgs;
}
private boolean isAsyncVoidReturnType(MethodParameter returnType,
@Nullable ReactiveAdapter reactiveAdapter) {

Loading…
Cancel
Save