Merge pull request #761 from garyrussell/INT-2955
* INT-2955: Fix Collection/Map Conversion
This commit is contained in:
@@ -27,6 +27,9 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.integration.MessageHeaders;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -106,10 +109,15 @@ public class BeanFactoryTypeConverter implements TypeConverter, BeanFactoryAware
|
||||
* INT-2630 Spring 3.1 now converts ALL arguments; we know we don't need to convert MessageHeaders
|
||||
* or MessageHistory; the MapToMap converter requires a no-arg constructor.
|
||||
* Also INT-2650 - don't convert large byte[]
|
||||
* This reverts the effective logic to Spring 3.0.
|
||||
*/
|
||||
if (sourceType != null && sourceType.isAssignableTo(targetType)) {
|
||||
return value;
|
||||
if (sourceType != null) {
|
||||
Class<?> sourceClass = sourceType.getType();
|
||||
Class<?> targetClass = targetType.getType();
|
||||
if ((sourceClass == MessageHeaders.class && targetClass == MessageHeaders.class) ||
|
||||
(sourceClass == MessageHistory.class && targetClass == MessageHistory.class) ||
|
||||
(sourceType.isAssignableTo(targetType) && ClassUtils.isPrimitiveArray(sourceClass))) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (conversionService.canConvert(sourceType, targetType)) {
|
||||
return conversionService.convert(value, sourceType, targetType);
|
||||
@@ -125,7 +133,7 @@ public class BeanFactoryTypeConverter implements TypeConverter, BeanFactoryAware
|
||||
editor.setValue(value);
|
||||
text = editor.getAsText();
|
||||
}
|
||||
if (String.class.isAssignableFrom(targetType.getClass())) {
|
||||
if (String.class.isAssignableFrom(targetType.getType())) {
|
||||
return text;
|
||||
}
|
||||
return convertValue(text, TypeDescriptor.valueOf(String.class), targetType);
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.integration.util;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
@@ -28,7 +30,12 @@ import static org.mockito.Mockito.when;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -44,9 +51,14 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageHeaders;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.context.NamedComponent;
|
||||
import org.springframework.integration.handler.MethodInvokingMessageProcessor;
|
||||
import org.springframework.integration.handler.ServiceActivatingHandler;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
|
||||
@@ -107,7 +119,7 @@ public class BeanFactoryTypeConverterTests {
|
||||
}
|
||||
});
|
||||
MessageHistory history = MessageHistory.read(message);
|
||||
assertSame(history, typeConverter.convertValue(history, TypeDescriptor.valueOf(MessageHeaders.class), TypeDescriptor.valueOf(MessageHeaders.class)));
|
||||
assertSame(history, typeConverter.convertValue(history, TypeDescriptor.valueOf(MessageHistory.class), TypeDescriptor.valueOf(MessageHistory.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,6 +151,128 @@ public class BeanFactoryTypeConverterTests {
|
||||
assertEquals("foo", typeConverter.convertValue(object, TypeDescriptor.valueOf(Object.class), TypeDescriptor.valueOf(String.class)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testMapOfMapOfCollectionIsConverted() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
conversionService.addConverter(new Converter<Foo, Bar>() {
|
||||
public Bar convert(Foo source) {
|
||||
return new Bar();
|
||||
}
|
||||
});
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
beanFactory.setConversionService(conversionService);
|
||||
typeConverter.setBeanFactory(beanFactory);
|
||||
Map<String, Map<String, Set<Foo>>> foos;
|
||||
Map<String, Map<String, Set<Bar>>> bars;
|
||||
|
||||
TypeDescriptor sourceType = TypeDescriptor.map(Map.class, null, null);
|
||||
TypeDescriptor targetType = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(Bar.class))));
|
||||
|
||||
Set<Foo> fooSet = new HashSet<Foo>();
|
||||
fooSet.add(new Foo());
|
||||
Map<String, Set<Foo>> fooMap = new HashMap<String, Set<Foo>>();
|
||||
fooMap.put("foo", fooSet);
|
||||
foos = new HashMap<String, Map<String, Set<Foo>>>();
|
||||
foos.put("foo", fooMap);
|
||||
|
||||
bars = (Map<String, Map<String, Set<Bar>>>) typeConverter.convertValue(foos, sourceType, targetType);
|
||||
assertTrue(bars.get("foo").get("foo").iterator().next() instanceof Bar);
|
||||
|
||||
Service service = new Service();
|
||||
MethodInvokingMessageProcessor<Service> processor = new MethodInvokingMessageProcessor<Service>(service, "handle");
|
||||
processor.setConversionService(conversionService);
|
||||
ServiceActivatingHandler handler = new ServiceActivatingHandler(processor);
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
handler.setOutputChannel(replyChannel);
|
||||
handler.handleMessage(new GenericMessage<Map<String, Map<String, Set<Foo>>>>(foos));
|
||||
Message<?> message = replyChannel.receive(0);
|
||||
assertNotNull(message);
|
||||
assertEquals("bar", message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionIsConverted() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
conversionService.addConverter(new Converter<Foo, Bar>() {
|
||||
public Bar convert(Foo source) {
|
||||
return new Bar();
|
||||
}
|
||||
});
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
beanFactory.setConversionService(conversionService);
|
||||
typeConverter.setBeanFactory(beanFactory);
|
||||
|
||||
Service service = new Service();
|
||||
MethodInvokingMessageProcessor<Service> processor = new MethodInvokingMessageProcessor<Service>(service, "handle");
|
||||
processor.setConversionService(conversionService);
|
||||
ServiceActivatingHandler handler = new ServiceActivatingHandler(processor);
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
handler.setOutputChannel(replyChannel);
|
||||
handler.handleMessage(new GenericMessage<Collection<Foo>>(Collections.singletonList(new Foo())));
|
||||
Message<?> message = replyChannel.receive(0);
|
||||
assertNotNull(message);
|
||||
assertEquals("baz", message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullArg() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
Object foo = typeConverter.convertValue(null, null, TypeDescriptor.valueOf(Bar.class));
|
||||
assertNull(foo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoidArg() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
Object foo = typeConverter.convertValue(null, null, TypeDescriptor.valueOf(Void.class));
|
||||
assertNull(foo);
|
||||
foo = typeConverter.convertValue(null, null, TypeDescriptor.valueOf(Void.TYPE));
|
||||
assertNull(foo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditorWithTargetString() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
Object foo = typeConverter.convertValue(uuid, TypeDescriptor.valueOf(UUID.class),
|
||||
TypeDescriptor.valueOf(String.class));
|
||||
assertEquals(uuid.toString(), foo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditorWithTargetFoo() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
final Foo foo = new Foo();
|
||||
conversionService.addConverter(new Converter<String, Foo>() {
|
||||
public Foo convert(String source) {
|
||||
return foo;
|
||||
}
|
||||
});
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
Object convertedFoo = typeConverter.convertValue(uuid, TypeDescriptor.valueOf(UUID.class),
|
||||
TypeDescriptor.valueOf(Foo.class));
|
||||
assertSame(foo, convertedFoo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateWithTargetUUID() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(conversionService);
|
||||
UUID uuid = UUID.randomUUID();
|
||||
Object converted = typeConverter.convertValue(uuid.toString(), TypeDescriptor.valueOf(String.class),
|
||||
TypeDescriptor.valueOf(UUID.class));
|
||||
assertEquals(uuid, converted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialConcurrency() throws Exception {
|
||||
ConversionService conversionService = mock(ConversionService.class); // can convert nothing so we drop down to P.E.s
|
||||
@@ -176,4 +310,25 @@ public class BeanFactoryTypeConverterTests {
|
||||
assertEquals(4, count.get());
|
||||
assertFalse(concurrentlyInGetDefaultEditor.get());
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
|
||||
}
|
||||
|
||||
public static class Bar {
|
||||
|
||||
}
|
||||
|
||||
public static class Service {
|
||||
|
||||
public String handle(Map<String, Map<String, Set<Bar>>> payload) {
|
||||
assertTrue(payload.get("foo").get("foo").iterator().next() instanceof Bar);
|
||||
return "bar";
|
||||
}
|
||||
|
||||
public String handle(Collection<Bar> payload) {
|
||||
assertTrue(payload.iterator().next() instanceof Bar);
|
||||
return "baz";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user