Commit d13b9a98 authored by Stephane Nicoll's avatar Stephane Nicoll

Auto-configure JMS MessageConverter

If a `MessageConverter` bean is available, we now associate it to the
created `JmsTemplate` and `JmsListenerContainerFactory`. That way,
registering a custom `MessageConverter` is all that's needed.

The JMS auto-configuration is now using the new `ObjectProvider` that
offers a nicer API to detect if a primary candidate is available for
optional collaborators.

Closes gh-4282
parent ad7cf484
...@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jms; ...@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory; import javax.jms.ConnectionFactory;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.destination.DestinationResolver; import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.Assert; import org.springframework.util.Assert;
...@@ -33,6 +34,8 @@ public final class DefaultJmsListenerContainerFactoryConfigurer { ...@@ -33,6 +34,8 @@ public final class DefaultJmsListenerContainerFactoryConfigurer {
private DestinationResolver destinationResolver; private DestinationResolver destinationResolver;
private MessageConverter messageConverter;
private JtaTransactionManager transactionManager; private JtaTransactionManager transactionManager;
private JmsProperties jmsProperties; private JmsProperties jmsProperties;
...@@ -46,6 +49,16 @@ public final class DefaultJmsListenerContainerFactoryConfigurer { ...@@ -46,6 +49,16 @@ public final class DefaultJmsListenerContainerFactoryConfigurer {
this.destinationResolver = destinationResolver; this.destinationResolver = destinationResolver;
} }
/**
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
* converter should be used.
* @param messageConverter the {@link MessageConverter}
* @since 1.4.0
*/
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
/** /**
* Set the {@link JtaTransactionManager} to use or {@code null} if the JTA support * Set the {@link JtaTransactionManager} to use or {@code null} if the JTA support
* should not be used. * should not be used.
...@@ -84,6 +97,9 @@ public final class DefaultJmsListenerContainerFactoryConfigurer { ...@@ -84,6 +97,9 @@ public final class DefaultJmsListenerContainerFactoryConfigurer {
if (this.destinationResolver != null) { if (this.destinationResolver != null) {
factory.setDestinationResolver(this.destinationResolver); factory.setDestinationResolver(this.destinationResolver);
} }
if (this.messageConverter != null) {
factory.setMessageConverter(this.messageConverter);
}
JmsProperties.Listener listener = this.jmsProperties.getListener(); JmsProperties.Listener listener = this.jmsProperties.getListener();
factory.setAutoStartup(listener.isAutoStartup()); factory.setAutoStartup(listener.isAutoStartup());
if (listener.getAcknowledgeMode() != null) { if (listener.getAcknowledgeMode() != null) {
......
...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jms; ...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory; import javax.jms.ConnectionFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi; import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
...@@ -27,6 +28,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -27,6 +28,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms; import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerConfigUtils; import org.springframework.jms.config.JmsListenerConfigUtils;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.destination.DestinationResolver; import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.JndiDestinationResolver; import org.springframework.jms.support.destination.JndiDestinationResolver;
import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager;
...@@ -42,11 +44,14 @@ import org.springframework.transaction.jta.JtaTransactionManager; ...@@ -42,11 +44,14 @@ import org.springframework.transaction.jta.JtaTransactionManager;
@ConditionalOnClass(EnableJms.class) @ConditionalOnClass(EnableJms.class)
class JmsAnnotationDrivenConfiguration { class JmsAnnotationDrivenConfiguration {
@Autowired(required = false) @Autowired
private DestinationResolver destinationResolver; private ObjectProvider<DestinationResolver> destinationResolver;
@Autowired
private ObjectProvider<JtaTransactionManager> transactionManager;
@Autowired(required = false) @Autowired
private JtaTransactionManager transactionManager; private ObjectProvider<MessageConverter> messageConverter;
@Autowired @Autowired
private JmsProperties properties; private JmsProperties properties;
...@@ -55,8 +60,9 @@ class JmsAnnotationDrivenConfiguration { ...@@ -55,8 +60,9 @@ class JmsAnnotationDrivenConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DefaultJmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryConfigurer() { public DefaultJmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryConfigurer() {
DefaultJmsListenerContainerFactoryConfigurer configurer = new DefaultJmsListenerContainerFactoryConfigurer(); DefaultJmsListenerContainerFactoryConfigurer configurer = new DefaultJmsListenerContainerFactoryConfigurer();
configurer.setDestinationResolver(this.destinationResolver); configurer.setDestinationResolver(this.destinationResolver.getIfUnique());
configurer.setTransactionManager(this.transactionManager); configurer.setTransactionManager(this.transactionManager.getIfUnique());
configurer.setMessageConverter(this.messageConverter.getIfUnique());
configurer.setJmsProperties(this.properties); configurer.setJmsProperties(this.properties);
return configurer; return configurer;
} }
......
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2016 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.
...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jms; ...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.jms;
import javax.jms.ConnectionFactory; import javax.jms.ConnectionFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
...@@ -29,6 +30,7 @@ import org.springframework.context.annotation.Configuration; ...@@ -29,6 +30,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.destination.DestinationResolver; import org.springframework.jms.support.destination.DestinationResolver;
/** /**
...@@ -50,8 +52,11 @@ public class JmsAutoConfiguration { ...@@ -50,8 +52,11 @@ public class JmsAutoConfiguration {
@Autowired @Autowired
private ConnectionFactory connectionFactory; private ConnectionFactory connectionFactory;
@Autowired(required = false) @Autowired
private DestinationResolver destinationResolver; private ObjectProvider<DestinationResolver> destinationResolver;
@Autowired
private ObjectProvider<MessageConverter> messageConverter;
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
...@@ -59,7 +64,10 @@ public class JmsAutoConfiguration { ...@@ -59,7 +64,10 @@ public class JmsAutoConfiguration {
JmsTemplate jmsTemplate = new JmsTemplate(this.connectionFactory); JmsTemplate jmsTemplate = new JmsTemplate(this.connectionFactory);
jmsTemplate.setPubSubDomain(this.properties.isPubSubDomain()); jmsTemplate.setPubSubDomain(this.properties.isPubSubDomain());
if (this.destinationResolver != null) { if (this.destinationResolver != null) {
jmsTemplate.setDestinationResolver(this.destinationResolver); jmsTemplate.setDestinationResolver(this.destinationResolver.getIfUnique());
}
if (this.messageConverter != null) {
jmsTemplate.setMessageConverter(this.messageConverter.getIfUnique());
} }
return jmsTemplate; return jmsTemplate;
} }
......
...@@ -32,6 +32,7 @@ import org.springframework.boot.test.EnvironmentTestUtils; ...@@ -32,6 +32,7 @@ import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jms.annotation.EnableJms; import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
...@@ -42,6 +43,7 @@ import org.springframework.jms.config.SimpleJmsListenerContainerFactory; ...@@ -42,6 +43,7 @@ import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer; import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -202,6 +204,20 @@ public class JmsAutoConfigurationTests { ...@@ -202,6 +204,20 @@ public class JmsAutoConfigurationTests {
.getPropertyValue("transactionManager")).isNull(); .getPropertyValue("transactionManager")).isNull();
} }
@Test
public void testDefaultContainerFactoryWithMessageConverters() {
this.context = createContext(MessageConvertersConfiguration.class,
EnableJmsConfiguration.class);
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context.getBean(
"jmsListenerContainerFactory", JmsListenerContainerFactory.class);
assertThat(jmsListenerContainerFactory.getClass())
.isEqualTo(DefaultJmsListenerContainerFactory.class);
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory) jmsListenerContainerFactory)
.createListenerContainer(mock(JmsListenerEndpoint.class));
assertThat(listenerContainer.getMessageConverter())
.isSameAs(this.context.getBean("myMessageConverter"));
}
@Test @Test
public void testCustomContainerFactoryWithConfigurer() { public void testCustomContainerFactoryWithConfigurer() {
this.context = doLoad( this.context = doLoad(
...@@ -219,6 +235,15 @@ public class JmsAutoConfigurationTests { ...@@ -219,6 +235,15 @@ public class JmsAutoConfigurationTests {
assertThat(listenerContainer.isAutoStartup()).isFalse(); assertThat(listenerContainer.isAutoStartup()).isFalse();
} }
@Test
public void testJmsTemplateWithMessageConverters() {
load(MessageConvertersConfiguration.class);
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
assertThat(jmsTemplate.getMessageConverter()).isSameAs(
this.context.getBean("myMessageConverter"));
}
@Test @Test
public void testPubSubDisabledByDefault() { public void testPubSubDisabledByDefault() {
load(TestConfiguration.class); load(TestConfiguration.class);
...@@ -452,6 +477,22 @@ public class JmsAutoConfigurationTests { ...@@ -452,6 +477,22 @@ public class JmsAutoConfigurationTests {
} }
@Configuration
protected static class MessageConvertersConfiguration {
@Bean
@Primary
public MessageConverter myMessageConverter() {
return mock(MessageConverter.class);
}
@Bean
public MessageConverter anotherMessageConverter() {
return mock(MessageConverter.class);
}
}
@Configuration @Configuration
protected static class TestConfiguration9 { protected static class TestConfiguration9 {
......
...@@ -3590,7 +3590,9 @@ beans: ...@@ -3590,7 +3590,9 @@ beans:
---- ----
NOTE: {spring-javadoc}/jms/core/JmsMessagingTemplate.{dc-ext}[`JmsMessagingTemplate`] NOTE: {spring-javadoc}/jms/core/JmsMessagingTemplate.{dc-ext}[`JmsMessagingTemplate`]
can be injected in a similar manner. can be injected in a similar manner. If a `DestinationResolver` or `MessageConverter`
beans are defined, they are associated automatically to the auto-configured
`JmsTemplate`.
...@@ -3599,7 +3601,8 @@ can be injected in a similar manner. ...@@ -3599,7 +3601,8 @@ can be injected in a similar manner.
When the JMS infrastructure is present, any bean can be annotated with `@JmsListener` to When the JMS infrastructure is present, any bean can be annotated with `@JmsListener` to
create a listener endpoint. If no `JmsListenerContainerFactory` has been defined, a create a listener endpoint. If no `JmsListenerContainerFactory` has been defined, a
default one is configured automatically. default one is configured automatically. If a `DestinationResolver` or `MessageConverter`
beans are defined, they are associated automatically to the default factory.
The default factory is transactional by default. If you are running in an infrastructure The default factory is transactional by default. If you are running in an infrastructure
where a `JtaTransactionManager` is present, it will be associated to the listener container where a `JtaTransactionManager` is present, it will be associated to the listener container
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment