use of org.springframework.messaging.handler.invocation.InvocableHandlerMethod in project spring-integration by spring-projects.
the class MessagingMethodInvokerHelper method findHandlerMethodsForTarget.
private Map<String, Map<Class<?>, HandlerMethod>> findHandlerMethodsForTarget(final Object targetObject, final Class<? extends Annotation> annotationType, final String methodName, final boolean requiresReply) {
Map<String, Map<Class<?>, HandlerMethod>> handlerMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> candidateMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> candidateMessageMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> fallbackMethods = new HashMap<>();
final Map<Class<?>, HandlerMethod> fallbackMessageMethods = new HashMap<>();
final AtomicReference<Class<?>> ambiguousFallbackType = new AtomicReference<>();
final AtomicReference<Class<?>> ambiguousFallbackMessageGenericType = new AtomicReference<>();
final Class<?> targetClass = getTargetClass(targetObject);
MethodFilter methodFilter = new UniqueMethodFilter(targetClass);
ReflectionUtils.doWithMethods(targetClass, method1 -> {
boolean matchesAnnotation = false;
if (method1.isBridge()) {
return;
}
if (isMethodDefinedOnObjectClass(method1)) {
return;
}
if (method1.getDeclaringClass().equals(Proxy.class)) {
return;
}
if (annotationType != null && AnnotationUtils.findAnnotation(method1, annotationType) != null) {
matchesAnnotation = true;
} else if (!Modifier.isPublic(method1.getModifiers())) {
return;
}
if (requiresReply && void.class.equals(method1.getReturnType())) {
return;
}
if (methodName != null && !methodName.equals(method1.getName())) {
return;
}
if (methodName == null && ObjectUtils.containsElement(new String[] { "start", "stop", "isRunning" }, method1.getName())) {
return;
}
HandlerMethod handlerMethod1;
try {
method1 = AopUtils.selectInvocableMethod(method1, org.springframework.util.ClassUtils.getUserClass(targetObject));
InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method1);
handlerMethod1 = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList);
checkSpelInvokerRequired(targetClass, method1, handlerMethod1);
} catch (IneligibleMethodException e) {
if (logger.isDebugEnabled()) {
logger.debug("Method [" + method1 + "] is not eligible for Message handling " + e.getMessage() + ".");
}
return;
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("Method [" + method1 + "] is not eligible for Message handling.", e);
}
return;
}
if (AnnotationUtils.getAnnotation(method1, Default.class) != null) {
Assert.state(this.defaultHandlerMethod == null, () -> "Only one method can be @Default, but there are more for: " + targetObject);
this.defaultHandlerMethod = handlerMethod1;
}
Class<?> targetParameterType = handlerMethod1.getTargetParameterType();
if (matchesAnnotation || annotationType == null) {
if (handlerMethod1.isMessageMethod()) {
if (candidateMessageMethods.containsKey(targetParameterType)) {
throw new IllegalArgumentException("Found more than one method match for type " + "[Message<" + targetParameterType + ">]");
}
candidateMessageMethods.put(targetParameterType, handlerMethod1);
} else {
if (candidateMethods.containsKey(targetParameterType)) {
String exceptionMessage = "Found more than one method match for ";
if (Void.class.equals(targetParameterType)) {
exceptionMessage += "empty parameter for 'payload'";
} else {
exceptionMessage += "type [" + targetParameterType + "]";
}
throw new IllegalArgumentException(exceptionMessage);
}
candidateMethods.put(targetParameterType, handlerMethod1);
}
} else {
if (handlerMethod1.isMessageMethod()) {
if (fallbackMessageMethods.containsKey(targetParameterType)) {
// we need to check for duplicate type matches,
// but only if we end up falling back
// and we'll only keep track of the first one
ambiguousFallbackMessageGenericType.compareAndSet(null, targetParameterType);
}
fallbackMessageMethods.put(targetParameterType, handlerMethod1);
} else {
if (fallbackMethods.containsKey(targetParameterType)) {
// we need to check for duplicate type matches,
// but only if we end up falling back
// and we'll only keep track of the first one
ambiguousFallbackType.compareAndSet(null, targetParameterType);
}
fallbackMethods.put(targetParameterType, handlerMethod1);
}
}
}, methodFilter);
if (candidateMethods.isEmpty() && candidateMessageMethods.isEmpty() && fallbackMethods.isEmpty() && fallbackMessageMethods.isEmpty()) {
findSingleSpecifMethodOnInterfacesIfProxy(targetObject, methodName, candidateMessageMethods, candidateMethods);
}
if (!candidateMethods.isEmpty() || !candidateMessageMethods.isEmpty()) {
handlerMethods.put(CANDIDATE_METHODS, candidateMethods);
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, candidateMessageMethods);
return handlerMethods;
}
if ((ambiguousFallbackType.get() != null || ambiguousFallbackMessageGenericType.get() != null) && ServiceActivator.class.equals(annotationType)) {
/*
* When there are ambiguous fallback methods,
* a Service Activator can finally fallback to RequestReplyExchanger.exchange(m).
* Ambiguous means > 1 method that takes the same payload type, or > 1 method
* that takes a Message with the same generic type.
*/
List<Method> frameworkMethods = new ArrayList<>();
Class<?>[] allInterfaces = org.springframework.util.ClassUtils.getAllInterfacesForClass(targetClass);
for (Class<?> iface : allInterfaces) {
try {
if ("org.springframework.integration.gateway.RequestReplyExchanger".equals(iface.getName())) {
frameworkMethods.add(targetClass.getMethod("exchange", Message.class));
if (logger.isDebugEnabled()) {
logger.debug(targetObject.getClass() + ": Ambiguous fallback methods; using RequestReplyExchanger.exchange()");
}
}
} catch (Exception e) {
// should never happen (but would fall through to errors below)
}
}
if (frameworkMethods.size() == 1) {
Method method = org.springframework.util.ClassUtils.getMostSpecificMethod(frameworkMethods.get(0), targetObject.getClass());
InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method);
HandlerMethod handlerMethod = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList);
checkSpelInvokerRequired(targetClass, method, handlerMethod);
handlerMethods.put(CANDIDATE_METHODS, Collections.singletonMap(Object.class, handlerMethod));
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, candidateMessageMethods);
return handlerMethods;
}
}
Assert.state(!fallbackMethods.isEmpty() || !fallbackMessageMethods.isEmpty(), "Target object of type [" + this.targetObject.getClass() + "] has no eligible methods for handling Messages.");
Assert.isNull(ambiguousFallbackType.get(), "Found ambiguous parameter type [" + ambiguousFallbackType + "] for method match: " + fallbackMethods.values());
Assert.isNull(ambiguousFallbackMessageGenericType.get(), "Found ambiguous parameter type [" + ambiguousFallbackMessageGenericType + "] for method match: " + fallbackMethods.values());
handlerMethods.put(CANDIDATE_METHODS, fallbackMethods);
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, fallbackMessageMethods);
return handlerMethods;
}
use of org.springframework.messaging.handler.invocation.InvocableHandlerMethod in project spring-integration by spring-projects.
the class MessagingMethodInvokerHelper method findSingleSpecifMethodOnInterfacesIfProxy.
private void findSingleSpecifMethodOnInterfacesIfProxy(final Object targetObject, final String methodName, Map<Class<?>, HandlerMethod> candidateMessageMethods, Map<Class<?>, HandlerMethod> candidateMethods) {
if (AopUtils.isAopProxy(targetObject)) {
final AtomicReference<Method> targetMethod = new AtomicReference<>();
final AtomicReference<Class<?>> targetClass = new AtomicReference<>();
Class<?>[] interfaces = ((Advised) targetObject).getProxiedInterfaces();
for (Class<?> clazz : interfaces) {
ReflectionUtils.doWithMethods(clazz, method1 -> {
if (targetMethod.get() != null) {
throw new IllegalStateException("Ambiguous method " + methodName + " on " + targetObject);
} else {
targetMethod.set(method1);
targetClass.set(clazz);
}
}, method12 -> method12.getName().equals(methodName));
}
Method theMethod = targetMethod.get();
if (theMethod != null) {
theMethod = org.springframework.util.ClassUtils.getMostSpecificMethod(theMethod, targetObject.getClass());
InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, theMethod);
HandlerMethod handlerMethod = new HandlerMethod(invocableHandlerMethod, this.canProcessMessageList);
checkSpelInvokerRequired(targetClass.get(), theMethod, handlerMethod);
Class<?> targetParameterType = handlerMethod.getTargetParameterType();
if (handlerMethod.isMessageMethod()) {
if (candidateMessageMethods.containsKey(targetParameterType)) {
throw new IllegalArgumentException("Found more than one method match for type " + "[Message<" + targetParameterType + ">]");
}
candidateMessageMethods.put(targetParameterType, handlerMethod);
} else {
if (candidateMethods.containsKey(targetParameterType)) {
String exceptionMessage = "Found more than one method match for ";
if (Void.class.equals(targetParameterType)) {
exceptionMessage += "empty parameter for 'payload'";
} else {
exceptionMessage += "type [" + targetParameterType + "]";
}
throw new IllegalArgumentException(exceptionMessage);
}
candidateMethods.put(targetParameterType, handlerMethod);
}
}
}
}
use of org.springframework.messaging.handler.invocation.InvocableHandlerMethod in project spring-cloud-stream by spring-cloud.
the class AbstractBinderTests method buildStreamListener.
private StreamListenerMessageHandler buildStreamListener(Class<?> handlerClass, String handlerMethodName, Class<?>... parameters) throws Exception {
String channelName = "reply_" + System.nanoTime();
GenericApplicationContext context = new GenericApplicationContext();
context.getBeanFactory().registerSingleton(channelName, new QueueChannel());
Method m = ReflectionUtils.findMethod(handlerClass, handlerMethodName, parameters);
InvocableHandlerMethod method = new InvocableHandlerMethod(this, m);
HandlerMethodArgumentResolverComposite resolver = new HandlerMethodArgumentResolverComposite();
CompositeMessageConverterFactory factory = new CompositeMessageConverterFactory();
resolver.addResolver(new PayloadArgumentResolver(factory.getMessageConverterForAllRegistered()));
method.setMessageMethodArgumentResolvers(resolver);
Constructor<?> c = ReflectionUtils.accessibleConstructor(StreamListenerMessageHandler.class, InvocableHandlerMethod.class, boolean.class, String[].class);
StreamListenerMessageHandler handler = (StreamListenerMessageHandler) c.newInstance(method, false, new String[] {});
handler.setOutputChannelName(channelName);
handler.setBeanFactory(context);
handler.afterPropertiesSet();
context.refresh();
return handler;
}
use of org.springframework.messaging.handler.invocation.InvocableHandlerMethod in project spring-cloud-stream by spring-cloud.
the class StreamListenerAnnotationBeanPostProcessor method afterSingletonsInstantiated.
@Override
public final void afterSingletonsInstantiated() {
this.injectAndPostProcessDependencies();
EvaluationContext evaluationContext = IntegrationContextUtils.getEvaluationContext(this.applicationContext.getBeanFactory());
for (Map.Entry<String, List<StreamListenerHandlerMethodMapping>> mappedBindingEntry : mappedListenerMethods.entrySet()) {
ArrayList<DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper> handlers = new ArrayList<>();
for (StreamListenerHandlerMethodMapping mapping : mappedBindingEntry.getValue()) {
final InvocableHandlerMethod invocableHandlerMethod = this.messageHandlerMethodFactory.createInvocableHandlerMethod(mapping.getTargetBean(), checkProxy(mapping.getMethod(), mapping.getTargetBean()));
StreamListenerMessageHandler streamListenerMessageHandler = new StreamListenerMessageHandler(invocableHandlerMethod, resolveExpressionAsBoolean(mapping.getCopyHeaders(), "copyHeaders"), springIntegrationProperties.getMessageHandlerNotPropagatedHeaders());
streamListenerMessageHandler.setApplicationContext(this.applicationContext);
streamListenerMessageHandler.setBeanFactory(this.applicationContext.getBeanFactory());
if (StringUtils.hasText(mapping.getDefaultOutputChannel())) {
streamListenerMessageHandler.setOutputChannelName(mapping.getDefaultOutputChannel());
}
streamListenerMessageHandler.afterPropertiesSet();
if (StringUtils.hasText(mapping.getCondition())) {
String conditionAsString = resolveExpressionAsString(mapping.getCondition(), "condition");
Expression condition = SPEL_EXPRESSION_PARSER.parseExpression(conditionAsString);
handlers.add(new DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper(condition, streamListenerMessageHandler));
} else {
handlers.add(new DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper(null, streamListenerMessageHandler));
}
}
if (handlers.size() > 1) {
for (DispatchingStreamListenerMessageHandler.ConditionalStreamListenerMessageHandlerWrapper handler : handlers) {
Assert.isTrue(handler.isVoid(), StreamListenerErrorMessages.MULTIPLE_VALUE_RETURNING_METHODS);
}
}
AbstractReplyProducingMessageHandler handler;
if (handlers.size() > 1 || handlers.get(0).getCondition() != null) {
handler = new DispatchingStreamListenerMessageHandler(handlers, evaluationContext);
} else {
handler = handlers.get(0).getStreamListenerMessageHandler();
}
handler.setApplicationContext(this.applicationContext);
handler.setChannelResolver(this.binderAwareChannelResolver);
handler.afterPropertiesSet();
this.applicationContext.getBeanFactory().registerSingleton(handler.getClass().getSimpleName() + handler.hashCode(), handler);
applicationContext.getBean(mappedBindingEntry.getKey(), SubscribableChannel.class).subscribe(handler);
}
this.mappedListenerMethods.clear();
}
use of org.springframework.messaging.handler.invocation.InvocableHandlerMethod in project spring-framework by spring-projects.
the class MessagingMessageListenerAdapter method createMessagingErrorMessage.
private String createMessagingErrorMessage(String description) {
InvocableHandlerMethod handlerMethod = getHandlerMethod();
StringBuilder sb = new StringBuilder(description).append('\n').append("Endpoint handler details:\n").append("Method [").append(handlerMethod.getMethod()).append("]\n").append("Bean [").append(handlerMethod.getBean()).append("]\n");
return sb.toString();
}
Aggregations