From 4522e654f3bdda6d8b2bbfb22673354ec07fe1f5 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Wed, 13 Feb 2019 17:04:57 +0100 Subject: [PATCH] GH-1612 Fixed regression caused by introducing custom argument resolvers Resolves #1612 --- .../SmartMessageMethodArgumentResolver.java | 9 +- .../config/SmartPayloadArgumentResolver.java | 7 +- .../stream/config/ArgumentResolversTests.java | 106 ++++++++++++++++++ 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/ArgumentResolversTests.java diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartMessageMethodArgumentResolver.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartMessageMethodArgumentResolver.java index 31b036793..dc2c643bf 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartMessageMethodArgumentResolver.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartMessageMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2016-2019 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. @@ -68,7 +68,7 @@ class SmartMessageMethodArgumentResolver extends MessageMethodArgumentResolver { Class payloadClass = message.getPayload().getClass(); - if (ClassUtils.isAssignable(payloadClass, targetPayloadType)) { + if (conversionNotRequired(payloadClass, targetPayloadType)) { return message; } Object payload = message.getPayload(); @@ -85,6 +85,11 @@ class SmartMessageMethodArgumentResolver extends MessageMethodArgumentResolver { return MessageBuilder.createMessage(payload, message.getHeaders()); } + private boolean conversionNotRequired(Class a, Class b) { + return b == Object.class + ? ClassUtils.isAssignable(a, b) : ClassUtils.isAssignable(b, a); + } + private Class getPayloadType(MethodParameter parameter) { Type genericParamType = parameter.getGenericParameterType(); ResolvableType resolvableType = ResolvableType.forType(genericParamType) diff --git a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartPayloadArgumentResolver.java b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartPayloadArgumentResolver.java index 6c73a3aaf..481ddbaaf 100644 --- a/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartPayloadArgumentResolver.java +++ b/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/config/SmartPayloadArgumentResolver.java @@ -108,7 +108,7 @@ class SmartPayloadArgumentResolver extends PayloadArgumentResolver { Class targetClass = parameter.getParameterType(); Class payloadClass = payload.getClass(); - if (ClassUtils.isAssignable(payloadClass, targetClass)) { + if (conversionNotRequired(payloadClass, targetClass)) { validate(message, parameter, payload); return payload; } @@ -130,6 +130,11 @@ class SmartPayloadArgumentResolver extends PayloadArgumentResolver { } } + private boolean conversionNotRequired(Class a, Class b) { + return b == Object.class + ? ClassUtils.isAssignable(a, b) : ClassUtils.isAssignable(b, a); + } + private String getParameterName(MethodParameter param) { String paramName = param.getParameterName(); return (paramName != null ? paramName : "Arg " + param.getParameterIndex()); diff --git a/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/ArgumentResolversTests.java b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/ArgumentResolversTests.java new file mode 100644 index 000000000..2a57b3e98 --- /dev/null +++ b/spring-cloud-stream/src/test/java/org/springframework/cloud/stream/config/ArgumentResolversTests.java @@ -0,0 +1,106 @@ +/* + * Copyright 2019-2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.stream.config; + +import java.lang.reflect.Method; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.core.MethodParameter; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.converter.MessageConverter; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.util.ReflectionUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * + * @author Oleg Zhurakousky + * + */ +public class ArgumentResolversTests { + + @SuppressWarnings({ "deprecation", "rawtypes", "unchecked" }) + @Test + public void testSmartPayloadArgumentResolver() throws Exception { + + SmartPayloadArgumentResolver resolver = new SmartPayloadArgumentResolver(new TestMessageConverter()); + + Object payload = "hello".getBytes(); + GenericMessage message = new GenericMessage(payload); + MethodParameter parameter = new MethodParameter(getMethod("byteArray", byte[].class), 0); + Object resolvedArgument = resolver.resolveArgument(parameter, message); + assertThat(resolvedArgument).isSameAs(payload); + + parameter = new MethodParameter(getMethod("object", Object.class), 0); + resolvedArgument = resolver.resolveArgument(parameter, message); + assertThat(resolvedArgument).isInstanceOf(Message.class); + + payload = new LinkedHashMap<>(); + message = new GenericMessage(payload); + parameter = new MethodParameter(getMethod("map", Map.class), 0); + resolvedArgument = resolver.resolveArgument(parameter, message); + assertThat(resolvedArgument).isSameAs(payload); + + parameter = new MethodParameter(getMethod("object", Object.class), 0); + resolvedArgument = resolver.resolveArgument(parameter, message); + assertThat(resolvedArgument).isInstanceOf(Message.class); + } + + private Method getMethod(String name, Class parameter) { + return ReflectionUtils.findMethod(this.getClass(), name, parameter); + } + + public void byteArray(byte[] p) { + + } + + public void byteArrayMessage(Message p) { + + } + + public void object(Object p) { + + } + @SuppressWarnings("rawtypes") + public void map(Map p) { + + } + + /* + * The whole point of this converter is to return something other + * then what is being resolved to simply validate when it is invoked + * vs. when it is not. + */ + private static class TestMessageConverter implements MessageConverter { + + @Override + public Object fromMessage(Message message, Class targetClass) { + return message; + } + + @Override + public Message toMessage(Object payload, MessageHeaders headers) { + return new GenericMessage<>(payload); + } + + } +}