Skip to content

Commit ef856b2

Browse files
artembilangaryrussell
authored andcommitted
GH-2936: Add custom converters for MongoDbMS
Fixes #2936 * Add `MongoDbMessageStore.setCustomConverters()` to allow to inject any custom converters for `payload` as well as header values **Cherry-pick to 5.1.x**
1 parent f992c05 commit ef856b2

File tree

3 files changed

+96
-14
lines changed

3 files changed

+96
-14
lines changed

spring-integration-mongodb/src/main/java/org/springframework/integration/mongodb/store/MongoDbMessageStore.java

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
package org.springframework.integration.mongodb.store;
1818

1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.Collection;
22+
import java.util.Collections;
2123
import java.util.HashMap;
2224
import java.util.Iterator;
2325
import java.util.List;
@@ -140,13 +142,12 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
140142

141143
private final String collectionName;
142144

143-
private volatile ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
145+
private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
144146

145147
private ApplicationContext applicationContext;
146148

147149
private String[] whiteListPatterns;
148150

149-
150151
/**
151152
* Create a MongoDbMessageStore using the provided {@link MongoDbFactory}.and the default collection name.
152153
* @param mongoDbFactory The mongodb factory.
@@ -186,14 +187,28 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
186187
* @param patterns the patterns.
187188
*/
188189
public void addWhiteListPatterns(String... patterns) {
189-
this.whiteListPatterns = patterns;
190+
this.whiteListPatterns = patterns != null ? Arrays.copyOf(patterns, patterns.length) : null;
191+
}
192+
193+
/**
194+
* Configure a set of converters to use in the {@link MappingMongoConverter}.
195+
* Must be instances of {@code org.springframework.core.convert.converter.Converter},
196+
* {@code org.springframework.core.convert.converter.ConverterFactory},
197+
* {@code org.springframework.core.convert.converter.GenericConverter} or
198+
* {@code org.springframework.data.convert.ConverterBuilder.ConverterAware}.
199+
* @param customConverters the converters to use.
200+
* @since 5.1.6
201+
*/
202+
public void setCustomConverters(Object... customConverters) {
203+
this.converter.setCustomConverters(customConverters);
190204
}
191205

192206
@Override
193207
public void afterPropertiesSet() throws Exception {
194208
if (this.applicationContext != null) {
195209
this.converter.setApplicationContext(this.applicationContext);
196210
}
211+
197212
this.converter.afterPropertiesSet();
198213

199214
IndexOperations indexOperations = this.template.indexOps(this.collectionName);
@@ -512,26 +527,38 @@ private static Map<String, Object> asMap(Bson bson) {
512527
*/
513528
private final class MessageReadingMongoConverter extends MappingMongoConverter {
514529

530+
private Object[] customConverters;
531+
515532
MessageReadingMongoConverter(MongoDbFactory mongoDbFactory,
516533
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
517534
super(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
518535
}
519536

537+
void setCustomConverters(Object... customConverters) {
538+
this.customConverters =
539+
customConverters != null ? Arrays.copyOf(customConverters, customConverters.length) : null;
540+
}
541+
520542
@Override
521543
public void afterPropertiesSet() {
522-
List<Object> customConverters = new ArrayList<>();
523-
customConverters.add(new MessageHistoryToDocumentConverter());
524-
customConverters.add(new DocumentToGenericMessageConverter());
525-
customConverters.add(new DocumentToMutableMessageConverter());
544+
List<Object> converters = new ArrayList<>();
545+
converters.add(new MessageHistoryToDocumentConverter());
546+
converters.add(new DocumentToGenericMessageConverter());
547+
converters.add(new DocumentToMutableMessageConverter());
526548
DocumentToErrorMessageConverter docToErrorMessageConverter = new DocumentToErrorMessageConverter();
527549
if (MongoDbMessageStore.this.whiteListPatterns != null) {
528550
docToErrorMessageConverter.deserializingConverter
529551
.addWhiteListPatterns(MongoDbMessageStore.this.whiteListPatterns);
530552
}
531-
customConverters.add(docToErrorMessageConverter);
532-
customConverters.add(new DocumentToAdviceMessageConverter());
533-
customConverters.add(new ThrowableToBytesConverter());
534-
this.setCustomConversions(new MongoCustomConversions(customConverters));
553+
converters.add(docToErrorMessageConverter);
554+
converters.add(new DocumentToAdviceMessageConverter());
555+
converters.add(new ThrowableToBytesConverter());
556+
557+
if (this.customConverters != null) {
558+
Collections.addAll(converters, this.customConverters);
559+
}
560+
561+
setCustomConversions(new MongoCustomConversions(converters));
535562
super.afterPropertiesSet();
536563
}
537564

spring-integration-mongodb/src/test/java/org/springframework/integration/mongodb/store/MongoDbMessageStoreTests.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,18 @@
1616

1717
package org.springframework.integration.mongodb.store;
1818

19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import java.util.concurrent.CountDownLatch;
22+
import java.util.concurrent.TimeUnit;
23+
24+
import org.junit.Test;
25+
26+
import org.springframework.core.convert.converter.Converter;
27+
import org.springframework.data.convert.WritingConverter;
1928
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
2029
import org.springframework.integration.store.MessageStore;
30+
import org.springframework.messaging.support.GenericMessage;
2131

2232
import com.mongodb.MongoClient;
2333

@@ -36,4 +46,49 @@ protected MessageStore getMessageStore() throws Exception {
3646
return mongoDbMessageStore;
3747
}
3848

49+
@Test
50+
public void testCustomConverter() throws Exception {
51+
MongoDbMessageStore mongoDbMessageStore =
52+
new MongoDbMessageStore(new SimpleMongoDbFactory(new MongoClient(), "test"));
53+
FooToBytesConverter fooToBytesConverter = new FooToBytesConverter();
54+
mongoDbMessageStore.setCustomConverters(fooToBytesConverter);
55+
mongoDbMessageStore.afterPropertiesSet();
56+
57+
mongoDbMessageStore.addMessage(new GenericMessage<>(new Foo("foo")));
58+
59+
assertThat(fooToBytesConverter.called.await(10, TimeUnit.SECONDS)).isTrue();
60+
}
61+
62+
private static class Foo {
63+
64+
String foo;
65+
66+
Foo(String foo) {
67+
this.foo = foo;
68+
}
69+
70+
@Override
71+
public String toString() {
72+
return foo;
73+
}
74+
75+
}
76+
77+
@WritingConverter
78+
private static class FooToBytesConverter implements Converter<Foo, byte[]> {
79+
80+
private final CountDownLatch called = new CountDownLatch(1);
81+
82+
@Override
83+
public byte[] convert(Foo source) {
84+
try {
85+
return source.toString().getBytes();
86+
}
87+
finally {
88+
this.called.countDown();
89+
}
90+
}
91+
92+
}
93+
3994
}

src/reference/asciidoc/mongodb.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ The `MongoDbMessageStore` expands the `Message` as a Mongo document with all nes
123123
It is useful when you need to have access to the `payload` or `headers` for auditing or analytics -- for example, against stored messages.
124124

125125
IMPORTANT: The `MongoDbMessageStore` uses a custom `MappingMongoConverter` implementation to store `Message` instances as MongoDB documents, and there are some limitations for the properties (`payload` and `header` values) of the `Message`.
126-
For example, there is no ability to configure custom converters for complex domain `payload` instances or `header` values.
127-
There is also no way to provide a custom `MongoTemplate` (or `MappingMongoConverter`).
128-
To achieve these capabilities, an alternative MongoDB `MessageStore` implementation has been introduced (we describe it next).
126+
127+
Starting with version 5.1.6, the `MongoDbMessageStore` can be configured with custom converters which are propagated into an internal `MappingMongoConverter` implementation.
128+
See `MongoDbMessageStore.setCustomConverters(Object... customConverters)` JavaDocs for more information.
129129

130130
Spring Integration 3.0 introduced the `ConfigurableMongoDbMessageStore`.
131131
It implements both the `MessageStore` and `MessageGroupStore` interfaces.

0 commit comments

Comments
 (0)