From 1018fcf36159aac10f3166744edd4b0be4994274 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Fri, 7 Nov 2014 12:57:53 -0500 Subject: [PATCH] INT-3556: Payload Conversion Documentation JIRA: https://jira.spring.io/browse/INT-3556 Clarify when a `GenericConverter` might be needed rather than a simple `Converter`. --- .../channel/DatatypeChannelTests.java | 70 +++++++++++++++++++ src/reference/docbook/endpoint.xml | 17 ++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/DatatypeChannelTests.java b/spring-integration-core/src/test/java/org/springframework/integration/channel/DatatypeChannelTests.java index 3a2a614cd9..02ef9d4158 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/channel/DatatypeChannelTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/DatatypeChannelTests.java @@ -16,13 +16,17 @@ package org.springframework.integration.channel; +import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.Collections; import java.util.Date; +import java.util.HashSet; +import java.util.Set; import org.junit.Test; @@ -31,13 +35,16 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.context.support.ConversionServiceFactoryBean; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter; import org.springframework.integration.support.utils.IntegrationUtils; import org.springframework.integration.test.util.TestUtils; +import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageDeliveryException; import org.springframework.messaging.MessagingException; @@ -199,6 +206,23 @@ public class DatatypeChannelTests { channel.send(new ErrorMessage(new Exception("test"))); } + @Test + public void genericConverters() { + QueueChannel channel = createChannel(Foo.class); + DefaultConversionService conversionService = new DefaultConversionService(); + conversionService.addConverter(new StringToBarConverter()); + conversionService.addConverter(new IntegerToBazConverter()); + DefaultDatatypeChannelMessageConverter converter = new DefaultDatatypeChannelMessageConverter(); + converter.setConversionService(conversionService); + channel.setMessageConverter(converter); + assertTrue(channel.send(new GenericMessage("foo"))); + Message out = channel.receive(0); + assertThat(out.getPayload(), instanceOf(Bar.class)); + assertTrue(channel.send(new GenericMessage(42))); + out = channel.receive(0); + assertThat(out.getPayload(), instanceOf(Baz.class)); + } + private static QueueChannel createChannel(Class ... datatypes) { QueueChannel channel = new QueueChannel(); @@ -207,4 +231,50 @@ public class DatatypeChannelTests { return channel; } + private static class Foo { + + } + + private static class Bar extends Foo { + + } + + private static class Baz extends Foo { + + } + + private static class StringToBarConverter implements GenericConverter { + + @Override + public Set getConvertibleTypes() { + Set pairs = new HashSet(); + pairs.add(new ConvertiblePair(String.class, Foo.class)); + pairs.add(new ConvertiblePair(String.class, Bar.class)); + return pairs; + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + return new Bar(); + } + + } + + private static class IntegerToBazConverter implements GenericConverter { + + @Override + public Set getConvertibleTypes() { + Set pairs = new HashSet(); + pairs.add(new ConvertiblePair(Integer.class, Foo.class)); + pairs.add(new ConvertiblePair(Integer.class, Baz.class)); + return pairs; + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + return new Baz(); + } + + } + } diff --git a/src/reference/docbook/endpoint.xml b/src/reference/docbook/endpoint.xml index 59c178591f..350ac5534c 100644 --- a/src/reference/docbook/endpoint.xml +++ b/src/reference/docbook/endpoint.xml @@ -593,8 +593,21 @@ any transaction configuration essentially allowing you to enhance the behavior o To register a Converter all you need is to implement org.springframework.core.convert.converter.Converter, org.springframework.core.convert.converter.GenericConverter or - org.springframework.core.convert.converter.ConverterFactory and define it via - convenient namespace support: + org.springframework.core.convert.converter.ConverterFactory. + + + The Converter implementation is the simplest and converts + from a single type to another. For more sophistication, such as converting to a class hierarchy, you would + implement a GenericConverter and possibly a ConditionalConverter. + These give you complete access to the from and to type descriptors + enabling complex conversions. For example, if you have an abstract class Foo that is + the target of your conversion (parameter type, channel data type etc) and you have two concrete implementations + Bar and Baz and you wish to convert to one or the other based + on the input type, the GenericConverter would be a good fit. Refer to the JavaDocs for + these interfaces for more information. + + + When you have implemented your converter, you can register it with convenient namespace support: ]]>