Move JmsHandlerMethodFactory to spring-messaging

This commit moves JmsHandlerMethodFactory and its default
implementation to the messaging abstraction. Working on a similar
support for AMQP revealed that this factory has nothing that is JMS
specific and is exactly identical in the case of AMQP.

Issue: SPR-12053
This commit is contained in:
Stephane Nicoll
2014-08-01 16:08:31 +02:00
parent 25decee1a4
commit 7d1e33d88d
15 changed files with 148 additions and 104 deletions

View File

@@ -112,10 +112,10 @@ import org.springframework.context.annotation.Import;
* // process incoming message
* }</pre>
*
* These features are abstracted by the {@link org.springframework.jms.config.JmsHandlerMethodFactory
* JmsHandlerMethodFactory} that is responsible to build the necessary invoker to process
* the annotated method. By default, {@link org.springframework.jms.config.DefaultJmsHandlerMethodFactory
* DefaultJmsHandlerMethodFactory} is used.
* These features are abstracted by the {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory
* MessageHandlerMethodFactory} that is responsible to build the necessary invoker to process
* the annotated method. By default, {@link org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
* DefaultMessageHandlerMethodFactory} is used.
*
* <p>When more control is desired, a {@code @Configuration} class may implement
* {@link JmsListenerConfigurer}. This allows access to the underlying
@@ -172,7 +172,7 @@ import org.springframework.context.annotation.Import;
* &#064;Override
* public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
* registrar.setEndpointRegistry(myJmsListenerEndpointRegistry());
* registrar.setJmsHandlerMethodFactory(myJmsHandlerMethodFactory);
* registrar.setMessageHandlerMethodFactory(myJmsHandlerMethodFactory);
* }
*
* &#064;Bean
@@ -206,7 +206,7 @@ import org.springframework.context.annotation.Import;
* </bean>
*
* <bean id="myJmsHandlerMethodFactory"
* class="org.springframework.jms.config.DefaultJmsHandlerMethodFactory">
* class="org.springframework.messaging.handler.support.DefaultJmsHandlerMethodFactory">
* <property name="validator" ref="myValidator"/>
* </bean>
*

View File

@@ -31,13 +31,13 @@ import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
import org.springframework.jms.config.JmsHandlerMethodFactory;
import org.springframework.jms.config.JmsListenerConfigUtils;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.JmsListenerEndpointRegistry;
import org.springframework.jms.config.MethodJmsListenerEndpoint;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -86,7 +86,7 @@ public class JmsListenerAnnotationBeanPostProcessor
private BeanFactory beanFactory;
private final JmsHandlerMethodFactoryAdapter jmsHandlerMethodFactory = new JmsHandlerMethodFactoryAdapter();
private final MessageHandlerMethodFactoryAdapter messageHandlerMethodFactory = new MessageHandlerMethodFactoryAdapter();
private final JmsListenerEndpointRegistrar registrar = new JmsListenerEndpointRegistrar();
@@ -115,15 +115,15 @@ public class JmsListenerAnnotationBeanPostProcessor
}
/**
* Set the {@link JmsHandlerMethodFactory} to use to configure the message
* Set the {@link MessageHandlerMethodFactory} to use to configure the message
* listener responsible to serve an endpoint detected by this processor.
* <p>By default, {@link DefaultJmsHandlerMethodFactory} is used and it
* <p>By default, {@link DefaultMessageHandlerMethodFactory} is used and it
* can be configured further to support additional method arguments
* or to customize conversion and validation support. See
* {@link DefaultJmsHandlerMethodFactory} Javadoc for more details.
* {@link DefaultMessageHandlerMethodFactory} Javadoc for more details.
*/
public void setJmsHandlerMethodFactory(JmsHandlerMethodFactory jmsHandlerMethodFactory) {
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(jmsHandlerMethodFactory);
public void setMessageHandlerMethodFactory(MessageHandlerMethodFactory messageHandlerMethodFactory) {
this.messageHandlerMethodFactory.setMessageHandlerMethodFactory(messageHandlerMethodFactory);
}
/**
@@ -163,9 +163,9 @@ public class JmsListenerAnnotationBeanPostProcessor
}
// Set the custom handler method factory once resolved by the configurer
JmsHandlerMethodFactory handlerMethodFactory = this.registrar.getJmsHandlerMethodFactory();
MessageHandlerMethodFactory handlerMethodFactory = this.registrar.getMessageHandlerMethodFactory();
if (handlerMethodFactory != null) {
this.jmsHandlerMethodFactory.setJmsHandlerMethodFactory(handlerMethodFactory);
this.messageHandlerMethodFactory.setMessageHandlerMethodFactory(handlerMethodFactory);
}
// Actually register all listeners
@@ -216,7 +216,7 @@ public class JmsListenerAnnotationBeanPostProcessor
MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint();
endpoint.setBean(bean);
endpoint.setMethod(method);
endpoint.setJmsHandlerMethodFactory(this.jmsHandlerMethodFactory);
endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory);
endpoint.setId(getEndpointId(jmsListener));
endpoint.setDestination(jmsListener.destination());
if (StringUtils.hasText(jmsListener.selector())) {
@@ -257,33 +257,33 @@ public class JmsListenerAnnotationBeanPostProcessor
/**
* An {@link JmsHandlerMethodFactory} adapter that offers a configurable underlying
* A {@link MessageHandlerMethodFactory} adapter that offers a configurable underlying
* instance to use. Useful if the factory to use is determined once the endpoints
* have been registered but not created yet.
* @see JmsListenerEndpointRegistrar#setJmsHandlerMethodFactory(JmsHandlerMethodFactory)
* @see JmsListenerEndpointRegistrar#setMessageHandlerMethodFactory
*/
private class JmsHandlerMethodFactoryAdapter implements JmsHandlerMethodFactory {
private class MessageHandlerMethodFactoryAdapter implements MessageHandlerMethodFactory {
private JmsHandlerMethodFactory jmsHandlerMethodFactory;
private MessageHandlerMethodFactory messageHandlerMethodFactory;
public void setJmsHandlerMethodFactory(JmsHandlerMethodFactory jmsHandlerMethodFactory) {
this.jmsHandlerMethodFactory = jmsHandlerMethodFactory;
public void setMessageHandlerMethodFactory(MessageHandlerMethodFactory messageHandlerMethodFactory) {
this.messageHandlerMethodFactory = messageHandlerMethodFactory;
}
@Override
public InvocableHandlerMethod createInvocableHandlerMethod(Object bean, Method method) {
return getJmsHandlerMethodFactory().createInvocableHandlerMethod(bean, method);
return getMessageHandlerMethodFactory().createInvocableHandlerMethod(bean, method);
}
private JmsHandlerMethodFactory getJmsHandlerMethodFactory() {
if (this.jmsHandlerMethodFactory == null) {
this.jmsHandlerMethodFactory = createDefaultJmsHandlerMethodFactory();
private MessageHandlerMethodFactory getMessageHandlerMethodFactory() {
if (this.messageHandlerMethodFactory == null) {
this.messageHandlerMethodFactory = createDefaultJmsHandlerMethodFactory();
}
return this.jmsHandlerMethodFactory;
return this.messageHandlerMethodFactory;
}
private JmsHandlerMethodFactory createDefaultJmsHandlerMethodFactory() {
DefaultJmsHandlerMethodFactory defaultFactory = new DefaultJmsHandlerMethodFactory();
private MessageHandlerMethodFactory createDefaultJmsHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory defaultFactory = new DefaultMessageHandlerMethodFactory();
defaultFactory.setBeanFactory(beanFactory);
defaultFactory.afterPropertiesSet();
return defaultFactory;

View File

@@ -70,7 +70,7 @@ class AnnotationDrivenJmsBeanDefinitionParser implements BeanDefinitionParser {
String handlerMethodFactory = element.getAttribute("handler-method-factory");
if (StringUtils.hasText(handlerMethodFactory)) {
builder.addPropertyReference("jmsHandlerMethodFactory", handlerMethodFactory);
builder.addPropertyReference("messageHandlerMethodFactory", handlerMethodFactory);
}
registerInfrastructureBean(parserContext, builder,

View File

@@ -1,189 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.config;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.messaging.converter.GenericMessageConverter;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.support.HeaderMethodArgumentResolver;
import org.springframework.messaging.handler.annotation.support.HeadersMethodArgumentResolver;
import org.springframework.messaging.handler.annotation.support.MessageMethodArgumentResolver;
import org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
/**
* The default {@link JmsHandlerMethodFactory} implementation creating an
* {@link InvocableHandlerMethod} with the necessary
* {@link HandlerMethodArgumentResolver} instances to detect and process
* all the use cases defined by {@link org.springframework.jms.annotation.JmsListener
* JmsListener}.
*
* <p>Extra method argument resolvers can be added to customize the method
* signature that can be handled.
*
* <p>By default, the validation process redirects to a no-op implementation, see
* {@link #setValidator(Validator)} to customize it. The {@link ConversionService}
* can be customized in a similar manner to tune how the message payload
* can be converted
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see #setConversionService
* @see #setValidator
* @see #setCustomArgumentResolvers
*/
public class DefaultJmsHandlerMethodFactory implements JmsHandlerMethodFactory, BeanFactoryAware, InitializingBean {
private ConversionService conversionService = new DefaultFormattingConversionService();
private MessageConverter messageConverter;
private Validator validator = new NoOpValidator();
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private final HandlerMethodArgumentResolverComposite argumentResolvers =
new HandlerMethodArgumentResolverComposite();
private BeanFactory beanFactory;
/**
* Set the {@link ConversionService} to use to convert the original
* message payload or headers.
* @see HeaderMethodArgumentResolver
* @see GenericMessageConverter
*/
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Set the {@link MessageConverter} to use. By default a {@link GenericMessageConverter}
* is used.
* @see GenericMessageConverter
*/
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
/**
* Set the Validator instance used for validating @Payload arguments
* @see org.springframework.validation.annotation.Validated
* @see org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* Set the list of custom {@code HandlerMethodArgumentResolver}s that will be used
* after resolvers for supported argument type.
* @param customArgumentResolvers the list of resolvers (never {@code null})
*/
public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> customArgumentResolvers) {
this.customArgumentResolvers = customArgumentResolvers;
}
/**
* Configure the complete list of supported argument types effectively overriding
* the ones configured by default. This is an advanced option. For most use cases
* it should be sufficient to use {@link #setCustomArgumentResolvers(java.util.List)}.
*/
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
if (argumentResolvers == null) {
this.argumentResolvers.clear();
return;
}
this.argumentResolvers.addResolvers(argumentResolvers);
}
/**
* A {@link BeanFactory} only needs to be available for placeholder resolution
* in handler method arguments; it's optional otherwise.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() {
if (this.messageConverter == null) {
this.messageConverter = new GenericMessageConverter(this.conversionService);
}
if (this.argumentResolvers.getResolvers().isEmpty()) {
this.argumentResolvers.addResolvers(initArgumentResolvers());
}
}
@Override
public InvocableHandlerMethod createInvocableHandlerMethod(Object bean, Method method) {
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(bean, method);
handlerMethod.setMessageMethodArgumentResolvers(argumentResolvers);
return handlerMethod;
}
protected List<HandlerMethodArgumentResolver> initArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
ConfigurableBeanFactory cbf = (this.beanFactory instanceof ConfigurableBeanFactory ?
(ConfigurableBeanFactory) this.beanFactory : null);
// Annotation-based argument resolution
resolvers.add(new HeaderMethodArgumentResolver(this.conversionService, cbf));
resolvers.add(new HeadersMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new MessageMethodArgumentResolver());
if (this.customArgumentResolvers != null) {
resolvers.addAll(this.customArgumentResolvers);
}
resolvers.add(new PayloadArgumentResolver(this.messageConverter, this.validator));
return resolvers;
}
private static final class NoOpValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
}
@Override
public void validate(Object target, Errors errors) {
}
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.config;
import java.lang.reflect.Method;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
/**
* A factory for {@link InvocableHandlerMethod} that is suitable to process
* an incoming JMS message.
*
* @author Stephane Nicoll
* @since 4.1
*/
public interface JmsHandlerMethodFactory {
/**
* Create the {@link InvocableHandlerMethod} that is able to process the specified
* JMS method endpoint.
* @param bean the bean instance
* @param method the method to invoke
* @return a JMS-specific {@link InvocableHandlerMethod} suitable for that method
*/
InvocableHandlerMethod createInvocableHandlerMethod(Object bean, Method method);
}

View File

@@ -22,6 +22,8 @@ import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
import org.springframework.util.Assert;
/**
@@ -37,7 +39,7 @@ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, Initializ
private JmsListenerEndpointRegistry endpointRegistry;
private JmsHandlerMethodFactory jmsHandlerMethodFactory;
private MessageHandlerMethodFactory messageHandlerMethodFactory;
private JmsListenerContainerFactory<?> containerFactory;
@@ -65,22 +67,22 @@ public class JmsListenerEndpointRegistrar implements BeanFactoryAware, Initializ
}
/**
* Set the {@link JmsHandlerMethodFactory} to use to configure the message
* Set the {@link MessageHandlerMethodFactory} to use to configure the message
* listener responsible to serve an endpoint detected by this processor.
* <p>By default, {@link DefaultJmsHandlerMethodFactory} is used and it
* <p>By default, {@link DefaultMessageHandlerMethodFactory} is used and it
* can be configured further to support additional method arguments
* or to customize conversion and validation support. See
* {@link DefaultJmsHandlerMethodFactory} javadoc for more details.
* {@link DefaultMessageHandlerMethodFactory} javadoc for more details.
*/
public void setJmsHandlerMethodFactory(JmsHandlerMethodFactory jmsHandlerMethodFactory) {
this.jmsHandlerMethodFactory = jmsHandlerMethodFactory;
public void setMessageHandlerMethodFactory(MessageHandlerMethodFactory messageHandlerMethodFactory) {
this.messageHandlerMethodFactory = messageHandlerMethodFactory;
}
/**
* Return the custom {@link JmsHandlerMethodFactory} to use, if any.
* Return the custom {@link MessageHandlerMethodFactory} to use, if any.
*/
public JmsHandlerMethodFactory getJmsHandlerMethodFactory() {
return this.jmsHandlerMethodFactory;
public MessageHandlerMethodFactory getMessageHandlerMethodFactory() {
return this.messageHandlerMethodFactory;
}
/**

View File

@@ -25,6 +25,7 @@ import org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -41,7 +42,7 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
private Method method;
private JmsHandlerMethodFactory jmsHandlerMethodFactory;
private MessageHandlerMethodFactory messageHandlerMethodFactory;
/**
@@ -67,22 +68,22 @@ public class MethodJmsListenerEndpoint extends AbstractJmsListenerEndpoint {
}
/**
* Set the {@link JmsHandlerMethodFactory} to use to build the
* Set the {@link MessageHandlerMethodFactory} to use to build the
* {@link InvocableHandlerMethod} responsible to manage the invocation
* of this endpoint.
*/
public void setJmsHandlerMethodFactory(JmsHandlerMethodFactory jmsHandlerMethodFactory) {
this.jmsHandlerMethodFactory = jmsHandlerMethodFactory;
public void setMessageHandlerMethodFactory(MessageHandlerMethodFactory messageHandlerMethodFactory) {
this.messageHandlerMethodFactory = messageHandlerMethodFactory;
}
@Override
protected MessagingMessageListenerAdapter createMessageListener(MessageListenerContainer container) {
Assert.state(this.jmsHandlerMethodFactory != null,
"Could not create message listener - message listener factory not set");
Assert.state(this.messageHandlerMethodFactory != null,
"Could not create message listener - MessageHandlerMethodFactory not set");
MessagingMessageListenerAdapter messageListener = createMessageListenerInstance();
InvocableHandlerMethod invocableHandlerMethod =
this.jmsHandlerMethodFactory.createInvocableHandlerMethod(getBean(), getMethod());
this.messageHandlerMethodFactory.createInvocableHandlerMethod(getBean(), getMethod());
messageListener.setHandlerMethod(invocableHandlerMethod);
String responseDestination = getDefaultResponseDestination();
if (StringUtils.hasText(responseDestination)) {

View File

@@ -63,16 +63,16 @@
<xsd:attribute name="handler-method-factory" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies a custom org.springframework.jms.config.JmsHandlerMethodFactory instance to
use to configure the message listener responsible to serve an endpoint detected by this
processor. By default, DefaultJmsHandlerMethodFactory is used and it can be configured
Specifies a custom org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory
instance to use to configure the message listener responsible to serve an endpoint detected by this
processor. By default, DefaultMessageHandlerMethodFactory is used and it can be configured
further to support additional method arguments or to customize conversion and validation
support. See org.springframework.jms.config.DefaultJmsHandlerMethodFactory Javadoc for
more details.
support. See org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
Javadoc for more details.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.jms.config.JmsHandlerMethodFactory"/>
<tool:expected-type type="org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>

View File

@@ -184,7 +184,7 @@ public abstract class AbstractJmsAnnotationDrivenTests {
/**
* Test for {@link ValidationBean} with a validator ({@link TestValidator}) specified
* in a custom {@link org.springframework.jms.config.DefaultJmsHandlerMethodFactory}.
* in a custom {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory}.
*
* The test should throw a {@link org.springframework.jms.listener.adapter.ListenerExecutionFailedException}
*/

View File

@@ -25,14 +25,12 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
import org.springframework.jms.config.JmsHandlerMethodFactory;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
import org.springframework.jms.config.JmsListenerContainerTestFactory;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.JmsListenerEndpointRegistry;
@@ -42,7 +40,6 @@ import org.springframework.jms.listener.adapter.MessageListenerAdapter;
import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException;
/**
*
* @author Stephane Nicoll
*/
public class EnableJmsTests extends AbstractJmsAnnotationDrivenTests {
@@ -202,12 +199,12 @@ public class EnableJmsTests extends AbstractJmsAnnotationDrivenTests {
@Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
registrar.setJmsHandlerMethodFactory(jmsHandlerMethodFactory());
registrar.setMessageHandlerMethodFactory(customMessageHandlerMethodFactory());
}
@Bean
public JmsHandlerMethodFactory jmsHandlerMethodFactory() {
DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
public MessageHandlerMethodFactory customMessageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setValidator(new TestValidator());
return factory;
}

View File

@@ -1,201 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.config;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestName;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.ByteArrayMessageConverter;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
/**
* @author Stephane Nicoll
*/
public class DefaultJmsHandlerMethodFactoryTests {
@Rule
public final TestName name = new TestName();
@Rule
public final ExpectedException thrown = ExpectedException.none();
private final SampleBean sample = new SampleBean();
@Test
public void customConversion() throws Exception {
DefaultJmsHandlerMethodFactory instance = createInstance();
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(SampleBean.class, String.class, new Converter<SampleBean, String>() {
@Override
public String convert(SampleBean source) {
return "foo bar";
}
});
instance.setConversionService(conversionService);
instance.afterPropertiesSet();
InvocableHandlerMethod invocableHandlerMethod =
createInvocableHandlerMethod(instance, "simpleString", String.class);
invocableHandlerMethod.invoke(MessageBuilder.withPayload(sample).build());
assertMethodInvocation(sample, "simpleString");
}
@Test
public void customConversionServiceFailure() throws Exception {
DefaultJmsHandlerMethodFactory instance = createInstance();
GenericConversionService conversionService = new GenericConversionService();
assertFalse("conversion service should fail to convert payload",
conversionService.canConvert(Integer.class, String.class));
instance.setConversionService(conversionService);
instance.afterPropertiesSet();
InvocableHandlerMethod invocableHandlerMethod =
createInvocableHandlerMethod(instance, "simpleString", String.class);
thrown.expect(MessageConversionException.class);
invocableHandlerMethod.invoke(MessageBuilder.withPayload(123).build());
}
@Test
public void customMessageConverterFailure() throws Exception {
DefaultJmsHandlerMethodFactory instance = createInstance();
MessageConverter messageConverter = new ByteArrayMessageConverter();
instance.setMessageConverter(messageConverter);
instance.afterPropertiesSet();
InvocableHandlerMethod invocableHandlerMethod =
createInvocableHandlerMethod(instance, "simpleString", String.class);
thrown.expect(MessageConversionException.class);
invocableHandlerMethod.invoke(MessageBuilder.withPayload(123).build());
}
@Test
public void customArgumentResolver() throws Exception {
DefaultJmsHandlerMethodFactory instance = createInstance();
List<HandlerMethodArgumentResolver> customResolvers = new ArrayList<HandlerMethodArgumentResolver>();
customResolvers.add(new CustomHandlerMethodArgumentResolver());
instance.setCustomArgumentResolvers(customResolvers);
instance.afterPropertiesSet();
InvocableHandlerMethod invocableHandlerMethod =
createInvocableHandlerMethod(instance, "customArgumentResolver", Locale.class);
invocableHandlerMethod.invoke(MessageBuilder.withPayload(123).build());
assertMethodInvocation(sample, "customArgumentResolver");
}
@Test
public void overrideArgumentResolvers() throws Exception {
DefaultJmsHandlerMethodFactory instance = createInstance();
List<HandlerMethodArgumentResolver> customResolvers = new ArrayList<HandlerMethodArgumentResolver>();
customResolvers.add(new CustomHandlerMethodArgumentResolver());
instance.setArgumentResolvers(customResolvers);
instance.afterPropertiesSet();
Message<String> message = MessageBuilder.withPayload("sample").build();
// This will work as the local resolver is set
InvocableHandlerMethod invocableHandlerMethod =
createInvocableHandlerMethod(instance, "customArgumentResolver", Locale.class);
invocableHandlerMethod.invoke(message);
assertMethodInvocation(sample, "customArgumentResolver");
// This won't work as no resolver is known for the payload
InvocableHandlerMethod invocableHandlerMethod2 =
createInvocableHandlerMethod(instance, "simpleString", String.class);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("No suitable resolver for");
invocableHandlerMethod2.invoke(message);
}
private void assertMethodInvocation(SampleBean bean, String methodName) {
assertTrue("Method " + methodName + " should have been invoked", bean.invocations.get(methodName));
}
private InvocableHandlerMethod createInvocableHandlerMethod(
DefaultJmsHandlerMethodFactory factory, String methodName, Class<?>... parameterTypes) {
return factory.createInvocableHandlerMethod(sample, getListenerMethod(methodName, parameterTypes));
}
private DefaultJmsHandlerMethodFactory createInstance() {
DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
factory.setBeanFactory(new StaticListableBeanFactory());
return factory;
}
private Method getListenerMethod(String methodName, Class<?>... parameterTypes) {
Method method = ReflectionUtils.findMethod(SampleBean.class, methodName, parameterTypes);
assertNotNull("no method found with name " + methodName + " and parameters " + Arrays.toString(parameterTypes));
return method;
}
static class SampleBean {
private final Map<String, Boolean> invocations = new HashMap<String, Boolean>();
public void simpleString(String value) {
invocations.put("simpleString", true);
}
public void customArgumentResolver(Locale locale) {
invocations.put("customArgumentResolver", true);
assertEquals("Wrong value for locale", Locale.getDefault(), locale);
}
}
static class CustomHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(Locale.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
return Locale.getDefault();
}
}
}

View File

@@ -36,6 +36,7 @@ import org.springframework.jms.listener.SessionAwareMessageListener;
import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
@@ -48,7 +49,7 @@ public class JmsListenerContainerFactoryIntegrationTests {
private final DefaultJmsListenerContainerFactory containerFactory = new DefaultJmsListenerContainerFactory();
private final DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
private final DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
private final JmsEndpointSampleBean sample = new JmsEndpointSampleBean();
@@ -88,11 +89,11 @@ public class JmsListenerContainerFactoryIntegrationTests {
private MethodJmsListenerEndpoint createMethodJmsEndpoint(
DefaultJmsHandlerMethodFactory factory, Method method) {
DefaultMessageHandlerMethodFactory factory, Method method) {
MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint();
endpoint.setBean(sample);
endpoint.setMethod(method);
endpoint.setJmsHandlerMethodFactory(factory);
endpoint.setMessageHandlerMethodFactory(factory);
return endpoint;
}
@@ -107,7 +108,7 @@ public class JmsListenerContainerFactoryIntegrationTests {
}
private void initializeFactory(DefaultJmsHandlerMethodFactory factory) {
private void initializeFactory(DefaultMessageHandlerMethodFactory factory) {
factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet();
}

View File

@@ -55,6 +55,7 @@ import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.handler.annotation.support.MethodArgumentTypeMismatchException;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
@@ -76,7 +77,7 @@ public class MethodJmsListenerEndpointTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
private final DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
private final DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
private final DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
@@ -103,7 +104,7 @@ public class MethodJmsListenerEndpointTests {
MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint();
endpoint.setBean(this);
endpoint.setMethod(getTestMethod());
endpoint.setJmsHandlerMethodFactory(factory);
endpoint.setMessageHandlerMethodFactory(factory);
assertNotNull(endpoint.createMessageListener(container));
}
@@ -304,7 +305,7 @@ public class MethodJmsListenerEndpointTests {
public void validatePayloadValid() throws JMSException {
String methodName = "validatePayload";
DefaultJmsHandlerMethodFactory customFactory = new DefaultJmsHandlerMethodFactory();
DefaultMessageHandlerMethodFactory customFactory = new DefaultMessageHandlerMethodFactory();
customFactory.setValidator(testValidator("invalid value"));
initializeFactory(customFactory);
@@ -317,7 +318,7 @@ public class MethodJmsListenerEndpointTests {
@Test
public void validatePayloadInvalid() throws JMSException {
DefaultJmsHandlerMethodFactory customFactory = new DefaultJmsHandlerMethodFactory();
DefaultMessageHandlerMethodFactory customFactory = new DefaultMessageHandlerMethodFactory();
customFactory.setValidator(testValidator("invalid value"));
Method method = getListenerMethod("validatePayload", String.class);
@@ -353,16 +354,16 @@ public class MethodJmsListenerEndpointTests {
}
private MessagingMessageListenerAdapter createInstance(
DefaultJmsHandlerMethodFactory factory, Method method, MessageListenerContainer container) {
DefaultMessageHandlerMethodFactory factory, Method method, MessageListenerContainer container) {
MethodJmsListenerEndpoint endpoint = new MethodJmsListenerEndpoint();
endpoint.setBean(sample);
endpoint.setMethod(method);
endpoint.setJmsHandlerMethodFactory(factory);
endpoint.setMessageHandlerMethodFactory(factory);
return endpoint.createMessageListener(container);
}
private MessagingMessageListenerAdapter createInstance(
DefaultJmsHandlerMethodFactory factory, Method method) {
DefaultMessageHandlerMethodFactory factory, Method method) {
return createInstance(factory, method, new SimpleMessageListenerContainer());
}
@@ -392,7 +393,7 @@ public class MethodJmsListenerEndpointTests {
assertTrue("Method " + methodName + " should have been invoked", bean.invocations.get(methodName));
}
private void initializeFactory(DefaultJmsHandlerMethodFactory factory) {
private void initializeFactory(DefaultMessageHandlerMethodFactory factory) {
factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet();
}

View File

@@ -27,7 +27,7 @@ import org.junit.Test;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.jms.StubTextMessage;
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.jms.support.JmsHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConversionException;
@@ -42,7 +42,7 @@ import static org.mockito.BDDMockito.*;
*/
public class MessagingMessageListenerAdapterTests {
private final DefaultJmsHandlerMethodFactory factory = new DefaultJmsHandlerMethodFactory();
private final DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
private final SampleBean sample = new SampleBean();
@@ -122,7 +122,7 @@ public class MessagingMessageListenerAdapterTests {
return adapter;
}
private void initializeFactory(DefaultJmsHandlerMethodFactory factory) {
private void initializeFactory(DefaultMessageHandlerMethodFactory factory) {
factory.setBeanFactory(new StaticListableBeanFactory());
factory.afterPropertiesSet();
}

View File

@@ -7,9 +7,9 @@
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.1.xsd">
<jms:annotation-driven handler-method-factory="jmsHandlerMethodFactory"/>
<jms:annotation-driven handler-method-factory="customMessageHandlerMethodFactory"/>
<bean id="jmsHandlerMethodFactory" class="org.springframework.jms.config.DefaultJmsHandlerMethodFactory">
<bean id="customMessageHandlerMethodFactory" class="org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory">
<property name="validator">
<bean class="org.springframework.jms.annotation.AbstractJmsAnnotationDrivenTests$TestValidator"/>
</property>