Skip to content

Commit d13b9a9

Browse files
committed
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
1 parent ad7cf48 commit d13b9a9

File tree

5 files changed

+86
-12
lines changed

5 files changed

+86
-12
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/DefaultJmsListenerContainerFactoryConfigurer.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import javax.jms.ConnectionFactory;
2020

2121
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
22+
import org.springframework.jms.support.converter.MessageConverter;
2223
import org.springframework.jms.support.destination.DestinationResolver;
2324
import org.springframework.transaction.jta.JtaTransactionManager;
2425
import org.springframework.util.Assert;
@@ -33,6 +34,8 @@ public final class DefaultJmsListenerContainerFactoryConfigurer {
3334

3435
private DestinationResolver destinationResolver;
3536

37+
private MessageConverter messageConverter;
38+
3639
private JtaTransactionManager transactionManager;
3740

3841
private JmsProperties jmsProperties;
@@ -46,6 +49,16 @@ void setDestinationResolver(DestinationResolver destinationResolver) {
4649
this.destinationResolver = destinationResolver;
4750
}
4851

52+
/**
53+
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
54+
* converter should be used.
55+
* @param messageConverter the {@link MessageConverter}
56+
* @since 1.4.0
57+
*/
58+
public void setMessageConverter(MessageConverter messageConverter) {
59+
this.messageConverter = messageConverter;
60+
}
61+
4962
/**
5063
* Set the {@link JtaTransactionManager} to use or {@code null} if the JTA support
5164
* should not be used.
@@ -84,6 +97,9 @@ public void configure(DefaultJmsListenerContainerFactory factory,
8497
if (this.destinationResolver != null) {
8598
factory.setDestinationResolver(this.destinationResolver);
8699
}
100+
if (this.messageConverter != null) {
101+
factory.setMessageConverter(this.messageConverter);
102+
}
87103
JmsProperties.Listener listener = this.jmsProperties.getListener();
88104
factory.setAutoStartup(listener.isAutoStartup());
89105
if (listener.getAcknowledgeMode() != null) {

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import javax.jms.ConnectionFactory;
2020

21+
import org.springframework.beans.factory.ObjectProvider;
2122
import org.springframework.beans.factory.annotation.Autowired;
2223
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
@@ -27,6 +28,7 @@
2728
import org.springframework.jms.annotation.EnableJms;
2829
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
2930
import org.springframework.jms.config.JmsListenerConfigUtils;
31+
import org.springframework.jms.support.converter.MessageConverter;
3032
import org.springframework.jms.support.destination.DestinationResolver;
3133
import org.springframework.jms.support.destination.JndiDestinationResolver;
3234
import org.springframework.transaction.jta.JtaTransactionManager;
@@ -42,11 +44,14 @@
4244
@ConditionalOnClass(EnableJms.class)
4345
class JmsAnnotationDrivenConfiguration {
4446

45-
@Autowired(required = false)
46-
private DestinationResolver destinationResolver;
47+
@Autowired
48+
private ObjectProvider<DestinationResolver> destinationResolver;
49+
50+
@Autowired
51+
private ObjectProvider<JtaTransactionManager> transactionManager;
4752

48-
@Autowired(required = false)
49-
private JtaTransactionManager transactionManager;
53+
@Autowired
54+
private ObjectProvider<MessageConverter> messageConverter;
5055

5156
@Autowired
5257
private JmsProperties properties;
@@ -55,8 +60,9 @@ class JmsAnnotationDrivenConfiguration {
5560
@ConditionalOnMissingBean
5661
public DefaultJmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryConfigurer() {
5762
DefaultJmsListenerContainerFactoryConfigurer configurer = new DefaultJmsListenerContainerFactoryConfigurer();
58-
configurer.setDestinationResolver(this.destinationResolver);
59-
configurer.setTransactionManager(this.transactionManager);
63+
configurer.setDestinationResolver(this.destinationResolver.getIfUnique());
64+
configurer.setTransactionManager(this.transactionManager.getIfUnique());
65+
configurer.setMessageConverter(this.messageConverter.getIfUnique());
6066
configurer.setJmsProperties(this.properties);
6167
return configurer;
6268
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfiguration.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2014 the original author or authors.
2+
* Copyright 2012-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import javax.jms.ConnectionFactory;
2020

21+
import org.springframework.beans.factory.ObjectProvider;
2122
import org.springframework.beans.factory.annotation.Autowired;
2223
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -29,6 +30,7 @@
2930
import org.springframework.context.annotation.Import;
3031
import org.springframework.jms.core.JmsMessagingTemplate;
3132
import org.springframework.jms.core.JmsTemplate;
33+
import org.springframework.jms.support.converter.MessageConverter;
3234
import org.springframework.jms.support.destination.DestinationResolver;
3335

3436
/**
@@ -50,16 +52,22 @@ public class JmsAutoConfiguration {
5052
@Autowired
5153
private ConnectionFactory connectionFactory;
5254

53-
@Autowired(required = false)
54-
private DestinationResolver destinationResolver;
55+
@Autowired
56+
private ObjectProvider<DestinationResolver> destinationResolver;
57+
58+
@Autowired
59+
private ObjectProvider<MessageConverter> messageConverter;
5560

5661
@Bean
5762
@ConditionalOnMissingBean
5863
public JmsTemplate jmsTemplate() {
5964
JmsTemplate jmsTemplate = new JmsTemplate(this.connectionFactory);
6065
jmsTemplate.setPubSubDomain(this.properties.isPubSubDomain());
6166
if (this.destinationResolver != null) {
62-
jmsTemplate.setDestinationResolver(this.destinationResolver);
67+
jmsTemplate.setDestinationResolver(this.destinationResolver.getIfUnique());
68+
}
69+
if (this.messageConverter != null) {
70+
jmsTemplate.setMessageConverter(this.messageConverter.getIfUnique());
6371
}
6472
return jmsTemplate;
6573
}

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3333
import org.springframework.context.annotation.Bean;
3434
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.context.annotation.Primary;
3536
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
3637
import org.springframework.jms.annotation.EnableJms;
3738
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
@@ -42,6 +43,7 @@
4243
import org.springframework.jms.core.JmsMessagingTemplate;
4344
import org.springframework.jms.core.JmsTemplate;
4445
import org.springframework.jms.listener.DefaultMessageListenerContainer;
46+
import org.springframework.jms.support.converter.MessageConverter;
4547
import org.springframework.transaction.jta.JtaTransactionManager;
4648

4749
import static org.assertj.core.api.Assertions.assertThat;
@@ -202,6 +204,20 @@ public void testDefaultContainerFactoryNoTransactionManager() {
202204
.getPropertyValue("transactionManager")).isNull();
203205
}
204206

207+
@Test
208+
public void testDefaultContainerFactoryWithMessageConverters() {
209+
this.context = createContext(MessageConvertersConfiguration.class,
210+
EnableJmsConfiguration.class);
211+
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context.getBean(
212+
"jmsListenerContainerFactory", JmsListenerContainerFactory.class);
213+
assertThat(jmsListenerContainerFactory.getClass())
214+
.isEqualTo(DefaultJmsListenerContainerFactory.class);
215+
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory) jmsListenerContainerFactory)
216+
.createListenerContainer(mock(JmsListenerEndpoint.class));
217+
assertThat(listenerContainer.getMessageConverter())
218+
.isSameAs(this.context.getBean("myMessageConverter"));
219+
}
220+
205221
@Test
206222
public void testCustomContainerFactoryWithConfigurer() {
207223
this.context = doLoad(
@@ -219,6 +235,15 @@ public void testCustomContainerFactoryWithConfigurer() {
219235
assertThat(listenerContainer.isAutoStartup()).isFalse();
220236
}
221237

238+
239+
@Test
240+
public void testJmsTemplateWithMessageConverters() {
241+
load(MessageConvertersConfiguration.class);
242+
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
243+
assertThat(jmsTemplate.getMessageConverter()).isSameAs(
244+
this.context.getBean("myMessageConverter"));
245+
}
246+
222247
@Test
223248
public void testPubSubDisabledByDefault() {
224249
load(TestConfiguration.class);
@@ -452,6 +477,22 @@ DataSourceTransactionManager transactionManager() {
452477

453478
}
454479

480+
@Configuration
481+
protected static class MessageConvertersConfiguration {
482+
483+
@Bean
484+
@Primary
485+
public MessageConverter myMessageConverter() {
486+
return mock(MessageConverter.class);
487+
}
488+
489+
@Bean
490+
public MessageConverter anotherMessageConverter() {
491+
return mock(MessageConverter.class);
492+
}
493+
494+
}
495+
455496
@Configuration
456497
protected static class TestConfiguration9 {
457498

spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3590,7 +3590,9 @@ beans:
35903590
----
35913591

35923592
NOTE: {spring-javadoc}/jms/core/JmsMessagingTemplate.{dc-ext}[`JmsMessagingTemplate`]
3593-
can be injected in a similar manner.
3593+
can be injected in a similar manner. If a `DestinationResolver` or `MessageConverter`
3594+
beans are defined, they are associated automatically to the auto-configured
3595+
`JmsTemplate`.
35943596

35953597

35963598

@@ -3599,7 +3601,8 @@ can be injected in a similar manner.
35993601

36003602
When the JMS infrastructure is present, any bean can be annotated with `@JmsListener` to
36013603
create a listener endpoint. If no `JmsListenerContainerFactory` has been defined, a
3602-
default one is configured automatically.
3604+
default one is configured automatically. If a `DestinationResolver` or `MessageConverter`
3605+
beans are defined, they are associated automatically to the default factory.
36033606

36043607
The default factory is transactional by default. If you are running in an infrastructure
36053608
where a `JtaTransactionManager` is present, it will be associated to the listener container

0 commit comments

Comments
 (0)