From 4ee09c89b5e1bf891f57e6f0b46382c28b487f2b Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 12 Feb 2018 21:30:26 -0500 Subject: [PATCH] Fix regression in MappingJackson2MessageConverter As of 4.3.13 MappingJackson2MessageConverter uses the MethodParameter hint to obtain generic type information but it needs to be careful, and nest one level, if the target parameter type has a Message wrapper. Issue: SPR-16486 --- .../MappingJackson2MessageConverter.java | 6 ++- .../MappingJackson2MessageConverterTests.java | 19 +++++++++- .../MessageMethodArgumentResolverTests.java | 37 +++++++++++++++++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java index 35f8aa16c2..eb725fc3ce 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/converter/MappingJackson2MessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,6 @@ import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; -import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; @@ -240,6 +239,9 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter { if (conversionHint instanceof MethodParameter) { MethodParameter param = (MethodParameter) conversionHint; param = param.nestedIfOptional(); + if (Message.class.isAssignableFrom(param.getParameterType())) { + param = param.nested(); + } Type genericParameterType = param.getNestedGenericParameterType(); Class contextClass = param.getContainingClass(); Type type = GenericTypeResolver.resolveType(genericParameterType, contextClass); diff --git a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java index e882dad7dd..17183f3a21 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/converter/MappingJackson2MessageConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** - * Test fixture for {@link org.springframework.messaging.converter.MappingJackson2MessageConverter}. + * Test fixture for {@link MappingJackson2MessageConverter}. * * @author Rossen Stoyanchev * @author Sebastien Deleuze @@ -150,6 +150,20 @@ public class MappingJackson2MessageConverterTests { assertEquals(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L), actual); } + @Test // SPR-16486 + public void fromMessageToMessageWithPojo() throws Exception { + MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); + String payload = "{\"string\":\"foo\"}"; + Message message = MessageBuilder.withPayload(payload.getBytes(StandardCharsets.UTF_8)).build(); + + Method method = getClass().getDeclaredMethod("handleMessage", Message.class); + MethodParameter param = new MethodParameter(method, 0); + Object actual = converter.fromMessage(message, Message.class, param); + + assertTrue(actual instanceof MyBean); + assertEquals("foo", ((MyBean) actual).getString()); + } + @Test public void toMessage() throws Exception { MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); @@ -242,6 +256,7 @@ public class MappingJackson2MessageConverterTests { void handleList(List payload) {} + void handleMessage(Message message) {} public static class MyBean { diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java index a7cb5507cc..4d095353c4 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/MessageMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import org.junit.rules.ExpectedException; import org.springframework.core.MethodParameter; import org.springframework.messaging.Message; +import org.springframework.messaging.converter.MappingJackson2MessageConverter; import org.springframework.messaging.converter.MessageConversionException; import org.springframework.messaging.converter.MessageConverter; import org.springframework.messaging.support.ErrorMessage; @@ -56,7 +57,7 @@ public class MessageMethodArgumentResolverTests { @Before public void setup() throws Exception { this.method = MessageMethodArgumentResolverTests.class.getDeclaredMethod("handle", - Message.class, Message.class, Message.class, Message.class, ErrorMessage.class); + Message.class, Message.class, Message.class, Message.class, ErrorMessage.class, Message.class); this.converter = mock(MessageConverter.class); this.resolver = new MessageMethodArgumentResolver(this.converter); @@ -222,6 +223,20 @@ public class MessageMethodArgumentResolverTests { this.resolver.resolveArgument(parameter, message); } + @Test // SPR-16486 + public void resolveWithJacksonConverter() throws Exception { + Message inMessage = MessageBuilder.withPayload("{\"foo\":\"bar\"}").build(); + MethodParameter parameter = new MethodParameter(this.method, 5); + + this.resolver = new MessageMethodArgumentResolver(new MappingJackson2MessageConverter()); + Object actual = this.resolver.resolveArgument(parameter, inMessage); + + assertTrue(actual instanceof Message); + Message outMessage = (Message) actual; + assertTrue(outMessage.getPayload() instanceof Foo); + assertEquals("bar", ((Foo) outMessage.getPayload()).getFoo()); + } + @SuppressWarnings("unused") private void handle( @@ -229,7 +244,23 @@ public class MessageMethodArgumentResolverTests { Message integerPayload, Message numberPayload, Message anyNumberPayload, - ErrorMessage subClass) { + ErrorMessage subClass, + Message fooPayload) { + } + + + static class Foo { + + private String foo; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } + } }