Revised method selection for JMS listeners (and their parameters)

Issue: SPR-13576
This commit is contained in:
Juergen Hoeller 2015-11-09 15:02:15 +01:00
parent d5efe4f983
commit da9c80c604
4 changed files with 138 additions and 80 deletions

View File

@ -18,7 +18,6 @@ package org.springframework.jms.annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -37,6 +36,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.jms.config.JmsListenerConfigUtils; import org.springframework.jms.config.JmsListenerConfigUtils;
@ -48,7 +48,6 @@ import org.springframework.messaging.handler.annotation.support.DefaultMessageHa
import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory; import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -194,26 +193,30 @@ public class JmsListenerAnnotationBeanPostProcessor
@Override @Override
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
if (!this.nonAnnotatedClasses.contains(bean.getClass())) { if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
Class<?> targetClass = AopUtils.getTargetClass(bean); Class<?> targetClass = AopUtils.getTargetClass(bean);
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() { Map<Method, Set<JmsListener>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
@Override new MethodIntrospector.MetadataLookup<Set<JmsListener>>() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { @Override
for (JmsListener jmsListener : public Set<JmsListener> inspect(Method method) {
AnnotationUtils.getRepeatableAnnotations(method, JmsListener.class, JmsListeners.class)) { Set<JmsListener> listenerMethods =
processJmsListener(jmsListener, method, bean); AnnotationUtils.getRepeatableAnnotations(method, JmsListener.class, JmsListeners.class);
annotatedMethods.add(method); return (!listenerMethods.isEmpty() ? listenerMethods : null);
} }
} });
});
if (annotatedMethods.isEmpty()) { if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(bean.getClass()); this.nonAnnotatedClasses.add(bean.getClass());
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("No @JmsListener annotations found on bean class: " + bean.getClass()); logger.trace("No @JmsListener annotations found on bean type: " + bean.getClass());
} }
} }
else { else {
// Non-empty set of methods // Non-empty set of methods
for (Map.Entry<Method, Set<JmsListener>> entry : annotatedMethods.entrySet()) {
Method method = entry.getKey();
for (JmsListener listener : entry.getValue()) {
processJmsListener(listener, method, bean);
}
}
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @JmsListener methods processed on bean '" + beanName + logger.debug(annotatedMethods.size() + " @JmsListener methods processed on bean '" + beanName +
"': " + annotatedMethods); "': " + annotatedMethods);
@ -223,29 +226,13 @@ public class JmsListenerAnnotationBeanPostProcessor
return bean; return bean;
} }
protected void processJmsListener(JmsListener jmsListener, Method method, Object bean) { protected void processJmsListener(JmsListener jmsListener, Method mostSpecificMethod, Object bean) {
if (AopUtils.isJdkDynamicProxy(bean)) { Method invocableMethod = MethodIntrospector.selectInvocableMethod(mostSpecificMethod, bean.getClass());
try {
// Found a @JmsListener method on the target class for this JDK proxy ->
// is it also present on the proxy itself?
method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
}
catch (SecurityException ex) {
ReflectionUtils.handleReflectionException(ex);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException(String.format(
"@JmsListener method '%s' found on bean target class '%s', " +
"but not found in any interface(s) for bean JDK proxy. Either " +
"pull the method up to an interface or switch to subclass (CGLIB) " +
"proxies by setting proxy-target-class/proxyTargetClass " +
"attribute to 'true'", method.getName(), method.getDeclaringClass().getSimpleName()));
}
}
MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint(); MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint();
endpoint.setBean(bean); endpoint.setBean(bean);
endpoint.setMethod(method); endpoint.setMethod(invocableMethod);
endpoint.setMostSpecificMethod(mostSpecificMethod);
endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory); endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory);
endpoint.setBeanFactory(this.beanFactory); endpoint.setBeanFactory(this.beanFactory);
endpoint.setId(getEndpointId(jmsListener)); endpoint.setId(getEndpointId(jmsListener));
@ -268,9 +255,9 @@ public class JmsListenerAnnotationBeanPostProcessor
factory = this.beanFactory.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class); factory = this.beanFactory.getBean(containerFactoryBeanName, JmsListenerContainerFactory.class);
} }
catch (NoSuchBeanDefinitionException ex) { catch (NoSuchBeanDefinitionException ex) {
throw new BeanInitializationException("Could not register jms listener endpoint on [" + throw new BeanInitializationException("Could not register JMS listener endpoint on [" +
method + "], no " + JmsListenerContainerFactory.class.getSimpleName() + " with id '" + mostSpecificMethod + "], no " + JmsListenerContainerFactory.class.getSimpleName() +
containerFactoryBeanName + "' was found in the application context", ex); " with id '" + containerFactoryBeanName + "' was found in the application context", ex);
} }
} }

View File

@ -39,6 +39,7 @@ import org.springframework.util.StringUtils;
* an incoming message for this endpoint. * an incoming message for this endpoint.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1 * @since 4.1
*/ */
public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint { public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
@ -47,6 +48,8 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
private Method method; private Method method;
private Method mostSpecificMethod;
private MessageHandlerMethodFactory messageHandlerMethodFactory; private MessageHandlerMethodFactory messageHandlerMethodFactory;
private BeanFactory beanFactory; private BeanFactory beanFactory;
@ -74,6 +77,29 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
return this.method; return this.method;
} }
/**
* Set the most specific method known for this endpoint's declaration.
* <p>In case of a proxy, this will be the method on the target class
* (if annotated itself, that is, if not just annotated in an interface).
* @since 4.2.3
*/
public void setMostSpecificMethod(Method mostSpecificMethod) {
this.mostSpecificMethod = mostSpecificMethod;
}
public Method getMostSpecificMethod() {
if (this.mostSpecificMethod != null) {
return this.mostSpecificMethod;
}
else if (AopUtils.isAopProxy(this.bean)) {
Class<?> target = AopProxyUtils.ultimateTargetClass(this.bean);
return AopUtils.getMostSpecificMethod(getMethod(), target);
}
else {
return getMethod();
}
}
/** /**
* Set the {@link MessageHandlerMethodFactory} to use to build the * Set the {@link MessageHandlerMethodFactory} to use to build the
* {@link InvocableHandlerMethod} responsible to manage the invocation * {@link InvocableHandlerMethod} responsible to manage the invocation
@ -134,8 +160,8 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
if (ann != null) { if (ann != null) {
Object[] destinations = ann.value(); Object[] destinations = ann.value();
if (destinations.length != 1) { if (destinations.length != 1) {
throw new IllegalStateException("Invalid @" + SendTo.class.getSimpleName() + " annotation on '" throw new IllegalStateException("Invalid @" + SendTo.class.getSimpleName() + " annotation on '" +
+ specificMethod + "' one destination must be set (got " + Arrays.toString(destinations) + ")"); specificMethod + "' one destination must be set (got " + Arrays.toString(destinations) + ")");
} }
return resolve((String) destinations[0]); return resolve((String) destinations[0]);
} }
@ -154,16 +180,6 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
} }
private Method getMostSpecificMethod() {
if (AopUtils.isAopProxy(this.bean)) {
Class<?> target = AopProxyUtils.ultimateTargetClass(this.bean);
return AopUtils.getMostSpecificMethod(getMethod(), target);
}
else {
return getMethod();
}
}
@Override @Override
protected StringBuilder getEndpointDescription() { protected StringBuilder getEndpointDescription() {
return super.getEndpointDescription() return super.getEndpointDescription()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,6 +26,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -58,8 +59,9 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
@Rule @Rule
public final ExpectedException thrown = ExpectedException.none(); public final ExpectedException thrown = ExpectedException.none();
@Test @Test
public void simpleMessageListener() { public void simpleMessageListener() throws Exception {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(
Config.class, SimpleMessageListenerTestBean.class); Config.class, SimpleMessageListenerTestBean.class);
@ -70,8 +72,9 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
JmsListenerEndpoint endpoint = container.getEndpoint(); JmsListenerEndpoint endpoint = container.getEndpoint();
assertEquals("Wrong endpoint type", MethodJmsListenerEndpoint.class, endpoint.getClass()); assertEquals("Wrong endpoint type", MethodJmsListenerEndpoint.class, endpoint.getClass());
MethodJmsListenerEndpoint methodEndpoint = (MethodJmsListenerEndpoint) endpoint; MethodJmsListenerEndpoint methodEndpoint = (MethodJmsListenerEndpoint) endpoint;
assertNotNull(methodEndpoint.getBean()); assertEquals(SimpleMessageListenerTestBean.class, methodEndpoint.getBean().getClass());
assertNotNull(methodEndpoint.getMethod()); assertEquals(SimpleMessageListenerTestBean.class.getMethod("handleIt", String.class), methodEndpoint.getMethod());
assertEquals(SimpleMessageListenerTestBean.class.getMethod("handleIt", String.class), methodEndpoint.getMostSpecificMethod());
SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(); SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
methodEndpoint.setupListenerContainer(listenerContainer); methodEndpoint.setupListenerContainer(listenerContainer);
@ -83,14 +86,20 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
} }
@Test @Test
public void metaAnnotationIsDiscovered() { public void metaAnnotationIsDiscovered() throws Exception {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(
Config.class, MetaAnnotationTestBean.class); Config.class, MetaAnnotationTestBean.class);
try { try {
JmsListenerContainerTestFactory factory = context.getBean(JmsListenerContainerTestFactory.class); JmsListenerContainerTestFactory factory = context.getBean(JmsListenerContainerTestFactory.class);
assertEquals("one container should have been registered", 1, factory.getListenerContainers().size()); assertEquals("one container should have been registered", 1, factory.getListenerContainers().size());
JmsListenerEndpoint endpoint = factory.getListenerContainers().get(0).getEndpoint(); JmsListenerEndpoint endpoint = factory.getListenerContainers().get(0).getEndpoint();
assertEquals("Wrong endpoint type", MethodJmsListenerEndpoint.class, endpoint.getClass());
MethodJmsListenerEndpoint methodEndpoint = (MethodJmsListenerEndpoint) endpoint;
assertEquals(MetaAnnotationTestBean.class, methodEndpoint.getBean().getClass());
assertEquals(MetaAnnotationTestBean.class.getMethod("handleIt", String.class), methodEndpoint.getMethod());
assertEquals(MetaAnnotationTestBean.class.getMethod("handleIt", String.class), methodEndpoint.getMostSpecificMethod());
assertEquals("metaTestQueue", ((AbstractJmsListenerEndpoint) endpoint).getDestination()); assertEquals("metaTestQueue", ((AbstractJmsListenerEndpoint) endpoint).getDestination());
} }
finally { finally {
@ -99,13 +108,21 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
} }
@Test @Test
public void sendToAnnotationFoundOnProxy() { public void sendToAnnotationFoundOnProxy() throws Exception {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(
Config.class, ProxyConfig.class, ProxyTestBean.class); Config.class, ProxyConfig.class, ProxyTestBean.class);
try { try {
JmsListenerContainerTestFactory factory = context.getBean(JmsListenerContainerTestFactory.class); JmsListenerContainerTestFactory factory = context.getBean(JmsListenerContainerTestFactory.class);
assertEquals("one container should have been registered", 1, factory.getListenerContainers().size()); assertEquals("one container should have been registered", 1, factory.getListenerContainers().size());
JmsListenerEndpoint endpoint = factory.getListenerContainers().get(0).getEndpoint(); JmsListenerEndpoint endpoint = factory.getListenerContainers().get(0).getEndpoint();
assertEquals("Wrong endpoint type", MethodJmsListenerEndpoint.class, endpoint.getClass());
MethodJmsListenerEndpoint methodEndpoint = (MethodJmsListenerEndpoint) endpoint;
assertTrue(AopUtils.isJdkDynamicProxy(methodEndpoint.getBean()));
assertTrue(methodEndpoint.getBean() instanceof SimpleService);
assertEquals(SimpleService.class.getMethod("handleIt", String.class), methodEndpoint.getMethod());
assertEquals(ProxyTestBean.class.getMethod("handleIt", String.class), methodEndpoint.getMostSpecificMethod());
Method m = ReflectionUtils.findMethod(endpoint.getClass(), "getDefaultResponseDestination"); Method m = ReflectionUtils.findMethod(endpoint.getClass(), "getDefaultResponseDestination");
ReflectionUtils.makeAccessible(m); ReflectionUtils.makeAccessible(m);
Object destination = ReflectionUtils.invokeMethod(m, endpoint); Object destination = ReflectionUtils.invokeMethod(m, endpoint);
@ -132,7 +149,6 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
@JmsListener(destination = "testQueue") @JmsListener(destination = "testQueue")
public void handleIt(String body) { public void handleIt(String body) {
} }
} }
@ -174,6 +190,7 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
} }
} }
@Configuration @Configuration
@EnableTransactionManagement @EnableTransactionManagement
static class ProxyConfig { static class ProxyConfig {
@ -182,15 +199,15 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
public PlatformTransactionManager transactionManager() { public PlatformTransactionManager transactionManager() {
return mock(PlatformTransactionManager.class); return mock(PlatformTransactionManager.class);
} }
} }
interface SimpleService { interface SimpleService {
void handleIt(String body); void handleIt(String body);
} }
@Component @Component
static class ProxyTestBean implements SimpleService { static class ProxyTestBean implements SimpleService {
@ -199,10 +216,10 @@ public class JmsListenerAnnotationBeanPostProcessorTests {
@JmsListener(destination = "testQueue") @JmsListener(destination = "testQueue")
@SendTo("foobar") @SendTo("foobar")
public void handleIt(String body) { public void handleIt(String body) {
} }
} }
@Component @Component
static class InvalidProxyTestBean implements SimpleService { static class InvalidProxyTestBean implements SimpleService {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,12 +29,14 @@ import javax.jms.TextMessage;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.support.StaticListableBeanFactory; import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.jms.StubTextMessage; import org.springframework.jms.StubTextMessage;
import org.springframework.jms.listener.DefaultMessageListenerContainer; import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.SessionAwareMessageListener; import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.jms.support.converter.MessageConversionException; import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter; import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory; import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@ -53,27 +55,65 @@ public class JmsListenerContainerFactoryIntegrationTests {
private final JmsEndpointSampleBean sample = new JmsEndpointSampleBean(); private final JmsEndpointSampleBean sample = new JmsEndpointSampleBean();
private JmsEndpointSampleInterface listener = sample;
@Before @Before
public void setup() { public void setup() {
initializeFactory(factory); initializeFactory(factory);
} }
@Test @Test
public void messageConverterUsedIfSet() throws JMSException { public void messageConverterUsedIfSet() throws JMSException {
containerFactory.setMessageConverter(new UpperCaseMessageConverter()); containerFactory.setMessageConverter(new UpperCaseMessageConverter());
MethodJmsListenerEndpoint endpoint = createDefaultMethodJmsEndpoint("expectFooBarUpperCase", String.class); MethodJmsListenerEndpoint endpoint = createDefaultMethodJmsEndpoint(
listener.getClass(), "handleIt", String.class, String.class);
Message message = new StubTextMessage("foo-bar"); Message message = new StubTextMessage("foo-bar");
message.setStringProperty("my-header", "my-value");
invokeListener(endpoint, message); invokeListener(endpoint, message);
assertListenerMethodInvocation("expectFooBarUpperCase"); assertListenerMethodInvocation("handleIt");
} }
@Test
public void parameterAnnotationWithJdkProxy() throws JMSException {
ProxyFactory pf = new ProxyFactory(sample);
listener = (JmsEndpointSampleInterface) pf.getProxy();
containerFactory.setMessageConverter(new UpperCaseMessageConverter());
MethodJmsListenerEndpoint endpoint = createDefaultMethodJmsEndpoint(
JmsEndpointSampleInterface.class, "handleIt", String.class, String.class);
Message message = new StubTextMessage("foo-bar");
message.setStringProperty("my-header", "my-value");
invokeListener(endpoint, message);
assertListenerMethodInvocation("handleIt");
}
@Test
public void parameterAnnotationWithCglibProxy() throws JMSException {
ProxyFactory pf = new ProxyFactory(sample);
pf.setProxyTargetClass(true);
listener = (JmsEndpointSampleBean) pf.getProxy();
containerFactory.setMessageConverter(new UpperCaseMessageConverter());
MethodJmsListenerEndpoint endpoint = createDefaultMethodJmsEndpoint(
JmsEndpointSampleBean.class, "handleIt", String.class, String.class);
Message message = new StubTextMessage("foo-bar");
message.setStringProperty("my-header", "my-value");
invokeListener(endpoint, message);
assertListenerMethodInvocation("handleIt");
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void invokeListener(JmsListenerEndpoint endpoint, Message message) throws JMSException { private void invokeListener(JmsListenerEndpoint endpoint, Message message) throws JMSException {
DefaultMessageListenerContainer messageListenerContainer = DefaultMessageListenerContainer messageListenerContainer = containerFactory.createListenerContainer(endpoint);
containerFactory.createListenerContainer(endpoint);
Object listener = messageListenerContainer.getMessageListener(); Object listener = messageListenerContainer.getMessageListener();
if (listener instanceof SessionAwareMessageListener) { if (listener instanceof SessionAwareMessageListener) {
((SessionAwareMessageListener<Message>) listener).onMessage(message, mock(Session.class)); ((SessionAwareMessageListener<Message>) listener).onMessage(message, mock(Session.class));
@ -87,40 +127,38 @@ public class JmsListenerContainerFactoryIntegrationTests {
assertTrue("Method " + methodName + " should have been invoked", sample.invocations.get(methodName)); assertTrue("Method " + methodName + " should have been invoked", sample.invocations.get(methodName));
} }
private MethodJmsListenerEndpoint createMethodJmsEndpoint(DefaultMessageHandlerMethodFactory factory, Method method) {
private MethodJmsListenerEndpoint createMethodJmsEndpoint(
DefaultMessageHandlerMethodFactory factory, Method method) {
MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint(); MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint();
endpoint.setBean(sample); endpoint.setBean(listener);
endpoint.setMethod(method); endpoint.setMethod(method);
endpoint.setMessageHandlerMethodFactory(factory); endpoint.setMessageHandlerMethodFactory(factory);
return endpoint; return endpoint;
} }
private MethodJmsListenerEndpoint createDefaultMethodJmsEndpoint(String methodName, Class<?>... parameterTypes) { private MethodJmsListenerEndpoint createDefaultMethodJmsEndpoint(Class<?> clazz, String methodName, Class<?>... paramTypes) {
return createMethodJmsEndpoint(this.factory, getListenerMethod(methodName, parameterTypes)); return createMethodJmsEndpoint(this.factory, ReflectionUtils.findMethod(clazz, methodName, paramTypes));
} }
private Method getListenerMethod(String methodName, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(JmsEndpointSampleBean.class, methodName, parameterTypes);
assertNotNull("no method found with name " + methodName + " and parameters " + Arrays.toString(parameterTypes));
return method;
}
private void initializeFactory(DefaultMessageHandlerMethodFactory factory) { private void initializeFactory(DefaultMessageHandlerMethodFactory factory) {
factory.setBeanFactory(new StaticListableBeanFactory()); factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet(); factory.afterPropertiesSet();
} }
static class JmsEndpointSampleBean { interface JmsEndpointSampleInterface {
void handleIt(@Payload String msg, @Header("my-header") String myHeader);
}
static class JmsEndpointSampleBean implements JmsEndpointSampleInterface {
private final Map<String, Boolean> invocations = new HashMap<String, Boolean>(); private final Map<String, Boolean> invocations = new HashMap<String, Boolean>();
public void expectFooBarUpperCase(@Payload String msg) { public void handleIt(@Payload String msg, @Header("my-header") String myHeader) {
invocations.put("expectFooBarUpperCase", true); invocations.put("handleIt", true);
assertEquals("Unexpected payload message", "FOO-BAR", msg); assertEquals("Unexpected payload message", "FOO-BAR", msg);
assertEquals("Unexpected header value", "my-value", myHeader);
} }
} }