GH-3052: Fix custom converters for lambdas

Fixes https://github.com/spring-projects/spring-integration/issues/3052

Starting with version `5.1`, a `LambdaMessageProcessor` is based on the
`MessageConverter` instead of plain `ConversionService`.
(A `ConfigurableCompositeMessageConverter` is used from the application
context.)
However a type conversion based on the `@IntegrationConverter` is lost
in the `GenericMessageConverter`  because it doesn't use an
`integrationConversionService` from the application context

* Change `ConfigurableCompositeMessageConverter` to configure a
 `GenericMessageConverter`  with an  `integrationConversionService`
 if any
* Fix `MessagingMethodInvokerHelper` to populate a `BeanFactory` into
its internal `ConfigurableCompositeMessageConverter`
* Ensure in the `LambdaMessageProcessorTests` that
`@IntegrationConverter` is applied for ``LambdaMessageProcessor` as well

**Cherry-pick to 5.1.x**
This commit is contained in:
Artem Bilan
2019-09-13 12:03:00 -04:00
committed by Gary Russell
parent 1e93d51697
commit 9272782a48
3 changed files with 109 additions and 27 deletions

View File

@@ -19,20 +19,26 @@ package org.springframework.integration.dsl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import java.util.Objects;
import java.util.function.Function;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.config.IntegrationConverter;
import org.springframework.integration.handler.GenericHandler;
import org.springframework.integration.handler.LambdaMessageProcessor;
import org.springframework.integration.support.converter.ConfigurableCompositeMessageConverter;
import org.springframework.integration.transformer.GenericTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.junit4.SpringRunner;
/**
@@ -41,8 +47,12 @@ import org.springframework.messaging.support.GenericMessage;
*
* @since 5.0
*/
@RunWith(SpringRunner.class)
public class LambdaMessageProcessorTests {
@Autowired
private BeanFactory beanFactory;
@Test
@SuppressWarnings("divzero")
public void testException() {
@@ -66,7 +76,7 @@ public class LambdaMessageProcessorTests {
}
}, null);
lmp.setBeanFactory(mock(BeanFactory.class));
lmp.setBeanFactory(this.beanFactory);
GenericMessage<String> testMessage = new GenericMessage<>("foo");
Object result = lmp.processMessage(testMessage);
assertThat(result).isSameAs(testMessage);
@@ -76,16 +86,24 @@ public class LambdaMessageProcessorTests {
public void testMessageAsArgumentLambda() {
LambdaMessageProcessor lmp = new LambdaMessageProcessor(
(GenericTransformer<Message<?>, Message<?>>) this::messageTransformer, null);
lmp.setBeanFactory(mock(BeanFactory.class));
lmp.setBeanFactory(this.beanFactory);
GenericMessage<String> testMessage = new GenericMessage<>("foo");
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> lmp.processMessage(testMessage))
.withCauseInstanceOf(ClassCastException.class);
}
@Test
public void testCustomConverter() {
LambdaMessageProcessor lmp = new LambdaMessageProcessor(Function.identity(), TestPojo.class);
lmp.setBeanFactory(this.beanFactory);
Object result = lmp.processMessage(new GenericMessage<>("foo"));
assertThat(result).isEqualTo(new TestPojo("foo"));
}
private void handle(GenericHandler<?> h) {
LambdaMessageProcessor lmp = new LambdaMessageProcessor(h, String.class);
lmp.setBeanFactory(getBeanFactory());
lmp.setBeanFactory(this.beanFactory);
lmp.processMessage(new GenericMessage<>("foo"));
}
@@ -95,12 +113,50 @@ public class LambdaMessageProcessorTests {
}
private BeanFactory getBeanFactory() {
BeanFactory mockBeanFactory = mock(BeanFactory.class);
given(mockBeanFactory.getBean(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME,
MessageConverter.class))
.willReturn(new ConfigurableCompositeMessageConverter());
return mockBeanFactory;
@Configuration
@EnableIntegration
public static class TestConfiguration {
@Bean
@IntegrationConverter
public Converter<String, TestPojo> testPojoConverter() {
return new Converter<String, TestPojo>() { // Cannot be lambda for explicit generic types
@Override
public TestPojo convert(String source) {
return new TestPojo(source);
}
};
}
}
private static class TestPojo {
private final String value;
TestPojo(String value) {
this.value = value;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof TestPojo)) {
return false;
}
TestPojo testPojo = (TestPojo) o;
return Objects.equals(this.value, testPojo.value);
}
@Override
public int hashCode() {
return Objects.hash(this.value);
}
}
}