From a591e345c1a00d5155ff2b1d9d1706c65d99125d Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Mon, 19 Feb 2018 16:23:33 -0500 Subject: [PATCH] GH-1098 Fixed argument resolution for typed collections Resolves #1098 --- .../config/BindingServiceConfiguration.java | 1 - ...cationJsonMessageMarshallingConverter.java | 15 +++--- .../binder/tck/ContentTypeTckTests.java | 46 ++++++++++++++++++- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java index a7c40536a..a31a35ed2 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/BindingServiceConfiguration.java @@ -228,5 +228,4 @@ public class BindingServiceConfiguration { } }; } - } diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/converter/ApplicationJsonMessageMarshallingConverter.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/converter/ApplicationJsonMessageMarshallingConverter.java index 1e0bf363a..ca4c5bda3 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/converter/ApplicationJsonMessageMarshallingConverter.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/converter/ApplicationJsonMessageMarshallingConverter.java @@ -17,6 +17,7 @@ package org.springframework.cloud.stream.converter; import java.io.IOException; +import java.lang.reflect.ParameterizedType; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -46,7 +47,6 @@ class ApplicationJsonMessageMarshallingConverter extends MappingJackson2MessageC private final Map, JavaType> typeCache = new ConcurrentHashMap<>(); - @Override protected Object convertToInternal(Object payload, @Nullable MessageHeaders headers, @Nullable Object conversionHint) { if (payload instanceof byte[]) { @@ -73,9 +73,13 @@ class ApplicationJsonMessageMarshallingConverter extends MappingJackson2MessageC */ conversionHint = null; } + else if (((MethodParameter)conversionHint).getGenericParameterType() instanceof ParameterizedType) { + ParameterizedTypeReference forType = ParameterizedTypeReference.forType(((MethodParameter)conversionHint).getGenericParameterType()); + result = convertParameterizedType(message, targetClass, forType); + } } else if (conversionHint instanceof ParameterizedTypeReference) { - result = convertParameterizedType(message, targetClass, conversionHint); + result = convertParameterizedType(message, targetClass, (ParameterizedTypeReference)conversionHint); } if (result == null) { @@ -90,15 +94,14 @@ class ApplicationJsonMessageMarshallingConverter extends MappingJackson2MessageC return result; } - private Object convertParameterizedType(Message message, Class targetClass, Object conversionHint) { + private Object convertParameterizedType(Message message, Class targetClass, ParameterizedTypeReference conversionHint) { ObjectMapper objectMapper = this.getObjectMapper(); Object payload = message.getPayload(); try { JavaType type = this.typeCache.get(conversionHint); if (type == null) { - type = objectMapper.getTypeFactory().constructType( - ((ParameterizedTypeReference) conversionHint).getType()); - this.typeCache.put((ParameterizedTypeReference) conversionHint, type); + type = objectMapper.getTypeFactory().constructType((conversionHint).getType()); + this.typeCache.put(conversionHint, type); } if (payload instanceof byte[]) { return objectMapper.readValue((byte[]) payload, type); diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java index 5e8f4631d..585e5a374 100644 --- a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/binder/tck/ContentTypeTckTests.java @@ -18,6 +18,7 @@ package org.springframework.cloud.stream.binder.tck; import java.nio.charset.StandardCharsets; import java.util.Collections; +import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; @@ -51,6 +52,7 @@ import org.springframework.messaging.support.MessageBuilder; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -381,6 +383,31 @@ public class ContentTypeTckTests { assertTrue(binder.getLastError().getPayload() instanceof MessageConversionException); } + + @Test + public void toCollectionWithParameterizedType() throws Exception { + ApplicationContext context = new SpringApplicationBuilder(CollectionWithParameterizedTypes.class) + .web(WebApplicationType.NONE) + .run("--spring.jmx.enabled=false"); + SourceDestination source = context.getBean(SourceDestination.class); + TargetDestination target = context.getBean(TargetDestination.class); + String jsonPayload = "[{\"person\":{\"name\":\"jon\"},\"id\":123},{\"person\":{\"name\":\"jane\"},\"id\":456}]"; + source.send(new GenericMessage(jsonPayload.getBytes())); + Message outputMessage = target.receive(); + assertThat(outputMessage.getPayload()).isEqualTo(jsonPayload.getBytes()); + } + + @EnableBinding(Processor.class) + @Import(SpringIntegrationBinderConfiguration.class) + public static class CollectionWithParameterizedTypes { + @StreamListener(Processor.INPUT) + @SendTo(Processor.OUTPUT) + public List> echo(List> value) { + assertTrue(value.get(0) instanceof Employee); + return value; + } + } + @EnableBinding(Processor.class) @Import(SpringIntegrationBinderConfiguration.class) public static class TextInJsonOutListener { @@ -391,8 +418,6 @@ public class ContentTypeTckTests { } } - - @EnableBinding(Processor.class) @Import(SpringIntegrationBinderConfiguration.class) public static class PojoToPojoStreamListener { @@ -508,6 +533,23 @@ public class ContentTypeTckTests { } } + public static class Employee

{ + private P person; + private int id; + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + public P getPerson() { + return person; + } + public void setPerson(P person) { + this.person = person; + } + } + public static class Person { private String name;