Search in sources :

Example 1 with InvocableHandlerMethod

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;
}
Also used : MutableMessage(org.springframework.integration.support.MutableMessage) Message(org.springframework.messaging.Message) HashMap(java.util.HashMap) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) ArrayList(java.util.ArrayList) MethodFilter(org.springframework.util.ReflectionUtils.MethodFilter) AnnotatedMethodFilter(org.springframework.integration.util.AnnotatedMethodFilter) FixedMethodFilter(org.springframework.integration.util.FixedMethodFilter) UniqueMethodFilter(org.springframework.integration.util.UniqueMethodFilter) AtomicReference(java.util.concurrent.atomic.AtomicReference) Method(java.lang.reflect.Method) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) UniqueMethodFilter(org.springframework.integration.util.UniqueMethodFilter) Default(org.springframework.integration.annotation.Default) ServiceActivator(org.springframework.integration.annotation.ServiceActivator) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) ConversionFailedException(org.springframework.core.convert.ConversionFailedException) MessageHandlingException(org.springframework.messaging.MessageHandlingException) EvaluationException(org.springframework.expression.EvaluationException) ConverterNotFoundException(org.springframework.core.convert.ConverterNotFoundException) MessageConversionException(org.springframework.messaging.converter.MessageConversionException) MethodArgumentResolutionException(org.springframework.messaging.handler.invocation.MethodArgumentResolutionException) NoSuchBeanDefinitionException(org.springframework.beans.factory.NoSuchBeanDefinitionException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with InvocableHandlerMethod

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);
            }
        }
    }
}
Also used : InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) AtomicReference(java.util.concurrent.atomic.AtomicReference) Method(java.lang.reflect.Method) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) Advised(org.springframework.aop.framework.Advised)

Example 3 with InvocableHandlerMethod

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;
}
Also used : GenericApplicationContext(org.springframework.context.support.GenericApplicationContext) QueueChannel(org.springframework.integration.channel.QueueChannel) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) Method(java.lang.reflect.Method) CompositeMessageConverterFactory(org.springframework.cloud.stream.converter.CompositeMessageConverterFactory) PayloadArgumentResolver(org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver) HandlerMethodArgumentResolverComposite(org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite) StreamListenerMessageHandler(org.springframework.cloud.stream.binding.StreamListenerMessageHandler)

Example 4 with InvocableHandlerMethod

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();
}
Also used : InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod) ArrayList(java.util.ArrayList) Expression(org.springframework.expression.Expression) AbstractReplyProducingMessageHandler(org.springframework.integration.handler.AbstractReplyProducingMessageHandler) ArrayList(java.util.ArrayList) List(java.util.List) EvaluationContext(org.springframework.expression.EvaluationContext) Map(java.util.Map) MultiValueMap(org.springframework.util.MultiValueMap) LinkedMultiValueMap(org.springframework.util.LinkedMultiValueMap) SubscribableChannel(org.springframework.messaging.SubscribableChannel)

Example 5 with InvocableHandlerMethod

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();
}
Also used : InvocableHandlerMethod(org.springframework.messaging.handler.invocation.InvocableHandlerMethod)

Aggregations

InvocableHandlerMethod (org.springframework.messaging.handler.invocation.InvocableHandlerMethod)14 Test (org.junit.jupiter.api.Test)7 Method (java.lang.reflect.Method)4 ArrayList (java.util.ArrayList)4 MessageConversionException (org.springframework.messaging.converter.MessageConversionException)3 Map (java.util.Map)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2 GenericConversionService (org.springframework.core.convert.support.GenericConversionService)2 HandlerMethodArgumentResolver (org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver)2 HashMap (java.util.HashMap)1 List (java.util.List)1 Advised (org.springframework.aop.framework.Advised)1 NoSuchBeanDefinitionException (org.springframework.beans.factory.NoSuchBeanDefinitionException)1 StreamListenerMessageHandler (org.springframework.cloud.stream.binding.StreamListenerMessageHandler)1 CompositeMessageConverterFactory (org.springframework.cloud.stream.converter.CompositeMessageConverterFactory)1 GenericApplicationContext (org.springframework.context.support.GenericApplicationContext)1 ConversionFailedException (org.springframework.core.convert.ConversionFailedException)1 ConverterNotFoundException (org.springframework.core.convert.ConverterNotFoundException)1 EvaluationContext (org.springframework.expression.EvaluationContext)1 EvaluationException (org.springframework.expression.EvaluationException)1