From ceccd9fbee3f7e1f04afed42ac696e4ad126b7a4 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 29 Jan 2019 17:28:15 -0500 Subject: [PATCH] Polish Updates to synchronize with newly created reactive equivalents. --- ...tractNamedValueMethodArgumentResolver.java | 79 +++++++++--------- ...inationVariableMethodArgumentResolver.java | 30 +++---- .../support/HeaderMethodArgumentResolver.java | 20 +++-- .../HeadersMethodArgumentResolver.java | 18 ++-- ...onVariableMethodArgumentResolverTests.java | 44 ++++------ .../HeaderMethodArgumentResolverTests.java | 82 +++++++------------ .../HeadersMethodArgumentResolverTests.java | 67 ++++++--------- 7 files changed, 140 insertions(+), 200 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java index 5f9b64c20e1..4d518867979 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java @@ -33,24 +33,20 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes import org.springframework.util.ClassUtils; /** - * Abstract base class for resolving method arguments from a named value. Message headers, - * and path variables are examples of named values. Each may have a name, a required flag, - * and a default value. + * Abstract base class to resolve method arguments from a named value, e.g. + * message headers or destination variables. Named values could have one or more + * of a name, a required flag, and a default value. * - *

Subclasses define how to do the following: - *

+ *

Subclasses only need to define specific steps such as how to obtain named + * value details from a method parameter, how to resolve to argument values, or + * how to handle missing values. * - *

A default value string can contain ${...} placeholders and Spring Expression - * Language {@code #{...}} expressions. For this to work a {@link ConfigurableBeanFactory} - * must be supplied to the class constructor. + *

A default value string can contain ${...} placeholders and Spring + * Expression Language {@code #{...}} expressions which will be resolved if a + * {@link ConfigurableBeanFactory} is supplied to the class constructor. * - *

A {@link ConversionService} may be used to apply type conversion to the resolved - * argument value if it doesn't match the method parameter type. + *

A {@link ConversionService} is used to to convert resolved String argument + * value to the expected target method parameter type. * * @author Rossen Stoyanchev * @author Juergen Hoeller @@ -71,11 +67,10 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle /** * Constructor with a {@link ConversionService} and a {@link BeanFactory}. - * @param conversionService conversion service for converting values to match the - * target method parameter type - * @param beanFactory a bean factory to use for resolving {@code ${...}} placeholder - * and {@code #{...}} SpEL expressions in default values, or {@code null} if default - * values are not expected to contain expressions + * @param conversionService conversion service for converting String values + * to the target method parameter type + * @param beanFactory a bean factory for resolving {@code ${...}} + * placeholders and {@code #{...}} SpEL expressions in default values */ protected AbstractNamedValueMethodArgumentResolver(ConversionService conversionService, @Nullable ConfigurableBeanFactory beanFactory) { @@ -87,12 +82,12 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle @Override - @Nullable public Object resolveArgument(MethodParameter parameter, Message message) throws Exception { + NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); - Object resolvedName = resolveStringValue(namedValueInfo.name); + Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); if (resolvedName == null) { throw new IllegalArgumentException( "Specified name must not resolve to null: [" + namedValueInfo.name + "]"); @@ -101,7 +96,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle Object arg = resolveArgumentInternal(nestedParameter, message, resolvedName.toString()); if (arg == null) { if (namedValueInfo.defaultValue != null) { - arg = resolveStringValue(namedValueInfo.defaultValue); + arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); } else if (namedValueInfo.required && !nestedParameter.isOptional()) { handleMissingValue(namedValueInfo.name, nestedParameter, message); @@ -109,7 +104,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType()); } else if ("".equals(arg) && namedValueInfo.defaultValue != null) { - arg = resolveStringValue(namedValueInfo.defaultValue); + arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); } if (parameter != nestedParameter || !ClassUtils.isAssignableValue(parameter.getParameterType(), arg)) { @@ -135,27 +130,31 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle } /** - * Create the {@link NamedValueInfo} object for the given method parameter. Implementations typically - * retrieve the method annotation by means of {@link MethodParameter#getParameterAnnotation(Class)}. + * Create the {@link NamedValueInfo} object for the given method parameter. + * Implementations typically retrieve the method annotation by means of + * {@link MethodParameter#getParameterAnnotation(Class)}. * @param parameter the method parameter * @return the named value information */ protected abstract NamedValueInfo createNamedValueInfo(MethodParameter parameter); /** - * Create a new NamedValueInfo based on the given NamedValueInfo with sanitized values. + * Fall back on the parameter name from the class file if necessary and + * replace {@link ValueConstants#DEFAULT_NONE} with null. */ private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) { String name = info.name; if (info.name.isEmpty()) { name = parameter.getParameterName(); if (name == null) { - throw new IllegalArgumentException("Name for argument type [" + parameter.getParameterType().getName() + - "] not available, and parameter name information not found in class file either."); + Class type = parameter.getParameterType(); + throw new IllegalArgumentException( + "Name for argument of type [" + type.getName() + "] not specified, " + + "and parameter name information not found in class file either."); } } - String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); - return new NamedValueInfo(name, info.required, defaultValue); + return new NamedValueInfo(name, info.required, + ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue); } /** @@ -163,7 +162,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle * potentially containing placeholders and expressions. */ @Nullable - private Object resolveStringValue(String value) { + private Object resolveEmbeddedValuesAndExpressions(String value) { if (this.configurableBeanFactory == null || this.expressionContext == null) { return value; } @@ -188,18 +187,19 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle throws Exception; /** - * Invoked when a named value is required, but - * {@link #resolveArgumentInternal(MethodParameter, Message, String)} returned {@code null} and - * there is no default value. Subclasses typically throw an exception in this case. + * Invoked when a value is required, but {@link #resolveArgumentInternal} + * returned {@code null} and there is no default value. Sub-classes can + * throw an appropriate exception for this case. * @param name the name for the value - * @param parameter the method parameter + * @param parameter the target method parameter * @param message the message being processed */ protected abstract void handleMissingValue(String name, MethodParameter parameter, Message message); /** - * A {@code null} results in a {@code false} value for {@code boolean}s or an - * exception for other primitives. + * One last chance to handle a possible null value. + * Specifically for booleans method parameters, use {@link Boolean#FALSE}. + * Also raise an ISE for primitive types. */ @Nullable private Object handleNullValue(String name, @Nullable Object value, Class paramType) { @@ -230,8 +230,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle /** - * Represents the information about a named value, including name, whether it's - * required and a default value. + * Represents a named value declaration. */ protected static class NamedValueInfo { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java index d9bad3db433..6fccd661e12 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java @@ -23,22 +23,20 @@ import org.springframework.core.convert.ConversionService; import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; +import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.ValueConstants; import org.springframework.util.Assert; /** - * Resolves method parameters annotated with - * {@link org.springframework.messaging.handler.annotation.DestinationVariable @DestinationVariable}. + * Resolve for {@link DestinationVariable @DestinationVariable} method parameters. * * @author Brian Clozel * @since 4.0 */ public class DestinationVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - /** - * The name of the header used to for template variables. - */ + /** The name of the header used to for template variables. */ public static final String DESTINATION_TEMPLATE_VARIABLES_HEADER = DestinationVariableMethodArgumentResolver.class.getSimpleName() + ".templateVariables"; @@ -55,26 +53,24 @@ public class DestinationVariableMethodArgumentResolver extends AbstractNamedValu @Override protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) { - DestinationVariable annotation = parameter.getParameterAnnotation(DestinationVariable.class); - Assert.state(annotation != null, "No DestinationVariable annotation"); - return new DestinationVariableNamedValueInfo(annotation); + DestinationVariable annot = parameter.getParameterAnnotation(DestinationVariable.class); + Assert.state(annot != null, "No DestinationVariable annotation"); + return new DestinationVariableNamedValueInfo(annot); } @Override @Nullable - protected Object resolveArgumentInternal(MethodParameter parameter, Message message, String name) - throws Exception { - - @SuppressWarnings("unchecked") - Map vars = - (Map) message.getHeaders().get(DESTINATION_TEMPLATE_VARIABLES_HEADER); - return (vars != null ? vars.get(name) : null); + @SuppressWarnings("unchecked") + protected Object resolveArgumentInternal(MethodParameter parameter, Message message, String name) { + MessageHeaders headers = message.getHeaders(); + Map vars = (Map) headers.get(DESTINATION_TEMPLATE_VARIABLES_HEADER); + return vars != null ? vars.get(name) : null; } @Override protected void handleMissingValue(String name, MethodParameter parameter, Message message) { - throw new MessageHandlingException(message, "Missing path template variable '" + name + - "' for method parameter type [" + parameter.getParameterType() + "]"); + throw new MessageHandlingException(message, "Missing path template variable '" + name + "' " + + "for method parameter type [" + parameter.getParameterType() + "]"); } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolver.java index 8e2e72d29ab..613991d739a 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolver.java @@ -33,10 +33,15 @@ import org.springframework.messaging.support.NativeMessageHeaderAccessor; import org.springframework.util.Assert; /** - * Resolves method parameters annotated with {@link Header @Header}. + * Resolver for {@link Header @Header} arguments. Headers are resolved from + * either the top-level header map or the nested + * {@link NativeMessageHeaderAccessor native} header map. * * @author Rossen Stoyanchev * @since 4.0 + * + * @see HeadersMethodArgumentResolver + * @see NativeMessageHeaderAccessor */ public class HeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { @@ -57,9 +62,9 @@ public class HeaderMethodArgumentResolver extends AbstractNamedValueMethodArgume @Override protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) { - Header annotation = parameter.getParameterAnnotation(Header.class); - Assert.state(annotation != null, "No Header annotation"); - return new HeaderNamedValueInfo(annotation); + Header annot = parameter.getParameterAnnotation(Header.class); + Assert.state(annot != null, "No Header annotation"); + return new HeaderNamedValueInfo(annot); } @Override @@ -72,10 +77,9 @@ public class HeaderMethodArgumentResolver extends AbstractNamedValueMethodArgume if (headerValue != null && nativeHeaderValue != null) { if (logger.isDebugEnabled()) { - logger.debug("Message headers contain two values for the same header '" + name + "', " + - "one in the top level header map and a second in the nested map with native headers. " + - "Using the value from top level map. " + - "Use 'nativeHeader.myHeader' to resolve to the value from the nested native header map."); + logger.debug("A value was found for '" + name + "', in both the top level header map " + + "and also in the nested map for native headers. Using the value from top level map. " + + "Use 'nativeHeader.myHeader' to resolve the native header."); } } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolver.java index 2d4a517946a..7d257f17ca3 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-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. @@ -29,12 +29,11 @@ import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.util.ReflectionUtils; /** - * {@link HandlerMethodArgumentResolver} for header method parameters. Resolves the - * following method parameters: + * Argument resolver for headers. Resolves the following method parameters: *

* * @author Rossen Stoyanchev @@ -58,7 +57,7 @@ public class HeadersMethodArgumentResolver implements HandlerMethodArgumentResol } else if (MessageHeaderAccessor.class == paramType) { MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, MessageHeaderAccessor.class); - return (accessor != null ? accessor : new MessageHeaderAccessor(message)); + return accessor != null ? accessor : new MessageHeaderAccessor(message); } else if (MessageHeaderAccessor.class.isAssignableFrom(paramType)) { MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, MessageHeaderAccessor.class); @@ -75,9 +74,8 @@ public class HeadersMethodArgumentResolver implements HandlerMethodArgumentResol } } else { - throw new IllegalStateException( - "Unexpected method parameter type " + paramType + "in method " + parameter.getMethod() + ". " - + "@Headers method arguments must be assignable to java.util.Map."); + throw new IllegalStateException("Unexpected parameter of type " + paramType + + " in method " + parameter.getMethod() + ". "); } } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java index 3af92e3b2e9..ea4b8559e21 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-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. @@ -16,23 +16,21 @@ package org.springframework.messaging.handler.annotation.support; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; -import org.junit.Before; import org.junit.Test; -import org.springframework.core.DefaultParameterNameDiscoverer; -import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.handler.annotation.DestinationVariable; +import org.springframework.messaging.handler.invocation.ResolvableMethod; import org.springframework.messaging.support.MessageBuilder; import static org.junit.Assert.*; +import static org.springframework.messaging.handler.annotation.MessagingPredicates.*; /** * Test fixture for {@link DestinationVariableMethodArgumentResolver} tests. @@ -41,33 +39,17 @@ import static org.junit.Assert.*; */ public class DestinationVariableMethodArgumentResolverTests { - private DestinationVariableMethodArgumentResolver resolver; + private final DestinationVariableMethodArgumentResolver resolver = + new DestinationVariableMethodArgumentResolver(new DefaultConversionService()); - private MethodParameter paramAnnotated; - private MethodParameter paramAnnotatedValue; - private MethodParameter paramNotAnnotated; + private final ResolvableMethod resolvable = + ResolvableMethod.on(getClass()).named("handleMessage").build(); - @Before - public void setup() throws Exception { - this.resolver = new DestinationVariableMethodArgumentResolver(new DefaultConversionService()); - - Method method = getClass().getDeclaredMethod("handleMessage", String.class, String.class, String.class); - this.paramAnnotated = new MethodParameter(method, 0); - this.paramAnnotatedValue = new MethodParameter(method, 1); - this.paramNotAnnotated = new MethodParameter(method, 2); - - this.paramAnnotated.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); - GenericTypeResolver.resolveParameterType(this.paramAnnotated, DestinationVariableMethodArgumentResolver.class); - this.paramAnnotatedValue.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); - GenericTypeResolver.resolveParameterType(this.paramAnnotatedValue, DestinationVariableMethodArgumentResolver.class); - } - @Test public void supportsParameter() { - assertTrue(resolver.supportsParameter(paramAnnotated)); - assertTrue(resolver.supportsParameter(paramAnnotatedValue)); - assertFalse(resolver.supportsParameter(paramNotAnnotated)); + assertTrue(resolver.supportsParameter(this.resolvable.annot(destinationVar().noValue()).arg())); + assertFalse(resolver.supportsParameter(this.resolvable.annotNotPresent(DestinationVariable.class).arg())); } @Test @@ -80,17 +62,19 @@ public class DestinationVariableMethodArgumentResolverTests { Message message = MessageBuilder.withPayload(new byte[0]).setHeader( DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER, vars).build(); - Object result = this.resolver.resolveArgument(this.paramAnnotated, message); + MethodParameter param = this.resolvable.annot(destinationVar().noValue()).arg(); + Object result = this.resolver.resolveArgument(param, message); assertEquals("bar", result); - result = this.resolver.resolveArgument(this.paramAnnotatedValue, message); + param = this.resolvable.annot(destinationVar("name")).arg(); + result = this.resolver.resolveArgument(param, message); assertEquals("value", result); } @Test(expected = MessageHandlingException.class) public void resolveArgumentNotFound() throws Exception { Message message = MessageBuilder.withPayload(new byte[0]).build(); - this.resolver.resolveArgument(this.paramAnnotated, message); + this.resolver.resolveArgument(this.resolvable.annot(destinationVar().noValue()).arg(), message); } @SuppressWarnings("unused") diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java index 61bf8854f6b..927809e4fed 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-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. @@ -16,7 +16,6 @@ package org.springframework.messaging.handler.annotation.support; -import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.Optional; @@ -25,19 +24,17 @@ import org.junit.Before; import org.junit.Test; import org.springframework.context.support.GenericApplicationContext; -import org.springframework.core.DefaultParameterNameDiscoverer; -import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; -import org.springframework.core.annotation.SynthesizingMethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.invocation.ResolvableMethod; import org.springframework.messaging.support.MessageBuilder; import org.springframework.messaging.support.NativeMessageHeaderAccessor; -import org.springframework.util.ReflectionUtils; import static org.junit.Assert.*; +import static org.springframework.messaging.handler.annotation.MessagingPredicates.*; /** * Test fixture for {@link HeaderMethodArgumentResolver} tests. @@ -50,46 +47,27 @@ public class HeaderMethodArgumentResolverTests { private HeaderMethodArgumentResolver resolver; - private MethodParameter paramRequired; - private MethodParameter paramNamedDefaultValueStringHeader; - private MethodParameter paramSystemPropertyDefaultValue; - private MethodParameter paramSystemPropertyName; - private MethodParameter paramNotAnnotated; - private MethodParameter paramOptional; - private MethodParameter paramNativeHeader; + private final ResolvableMethod resolvable = ResolvableMethod.on(getClass()).named("handleMessage").build(); @Before public void setup() { - @SuppressWarnings("resource") - GenericApplicationContext cxt = new GenericApplicationContext(); - cxt.refresh(); - this.resolver = new HeaderMethodArgumentResolver(new DefaultConversionService(), cxt.getBeanFactory()); - - Method method = ReflectionUtils.findMethod(getClass(), "handleMessage", (Class[]) null); - this.paramRequired = new SynthesizingMethodParameter(method, 0); - this.paramNamedDefaultValueStringHeader = new SynthesizingMethodParameter(method, 1); - this.paramSystemPropertyDefaultValue = new SynthesizingMethodParameter(method, 2); - this.paramSystemPropertyName = new SynthesizingMethodParameter(method, 3); - this.paramNotAnnotated = new SynthesizingMethodParameter(method, 4); - this.paramOptional = new SynthesizingMethodParameter(method, 5); - this.paramNativeHeader = new SynthesizingMethodParameter(method, 6); - - this.paramRequired.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); - GenericTypeResolver.resolveParameterType(this.paramRequired, HeaderMethodArgumentResolver.class); + GenericApplicationContext context = new GenericApplicationContext(); + context.refresh(); + this.resolver = new HeaderMethodArgumentResolver(new DefaultConversionService(), context.getBeanFactory()); } @Test public void supportsParameter() { - assertTrue(resolver.supportsParameter(paramNamedDefaultValueStringHeader)); - assertFalse(resolver.supportsParameter(paramNotAnnotated)); + assertTrue(this.resolver.supportsParameter(this.resolvable.annot(headerPlain()).arg())); + assertFalse(this.resolver.supportsParameter(this.resolvable.annotNotPresent(Header.class).arg())); } @Test public void resolveArgument() throws Exception { Message message = MessageBuilder.withPayload(new byte[0]).setHeader("param1", "foo").build(); - Object result = this.resolver.resolveArgument(this.paramRequired, message); + Object result = this.resolver.resolveArgument(this.resolvable.annot(headerPlain()).arg(), message); assertEquals("foo", result); } @@ -98,7 +76,7 @@ public class HeaderMethodArgumentResolverTests { TestMessageHeaderAccessor headers = new TestMessageHeaderAccessor(); headers.setNativeHeader("param1", "foo"); Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); - assertEquals("foo", this.resolver.resolveArgument(this.paramRequired, message)); + assertEquals("foo", this.resolver.resolveArgument(this.resolvable.annot(headerPlain()).arg(), message)); } @Test @@ -108,20 +86,23 @@ public class HeaderMethodArgumentResolverTests { headers.setNativeHeader("param1", "native-foo"); Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); - assertEquals("foo", this.resolver.resolveArgument(this.paramRequired, message)); - assertEquals("native-foo", this.resolver.resolveArgument(this.paramNativeHeader, message)); + assertEquals("foo", this.resolver.resolveArgument( + this.resolvable.annot(headerPlain()).arg(), message)); + + assertEquals("native-foo", this.resolver.resolveArgument( + this.resolvable.annot(header("nativeHeaders.param1")).arg(), message)); } @Test(expected = MessageHandlingException.class) public void resolveArgumentNotFound() throws Exception { Message message = MessageBuilder.withPayload(new byte[0]).build(); - this.resolver.resolveArgument(this.paramRequired, message); + this.resolver.resolveArgument(this.resolvable.annot(headerPlain()).arg(), message); } @Test public void resolveArgumentDefaultValue() throws Exception { Message message = MessageBuilder.withPayload(new byte[0]).build(); - Object result = this.resolver.resolveArgument(this.paramNamedDefaultValueStringHeader, message); + Object result = this.resolver.resolveArgument(this.resolvable.annot(header("name", "bar")).arg(), message); assertEquals("bar", result); } @@ -130,7 +111,8 @@ public class HeaderMethodArgumentResolverTests { System.setProperty("systemProperty", "sysbar"); try { Message message = MessageBuilder.withPayload(new byte[0]).build(); - Object result = resolver.resolveArgument(paramSystemPropertyDefaultValue, message); + MethodParameter param = this.resolvable.annot(header("name", "#{systemProperties.systemProperty}")).arg(); + Object result = resolver.resolveArgument(param, message); assertEquals("sysbar", result); } finally { @@ -143,7 +125,8 @@ public class HeaderMethodArgumentResolverTests { System.setProperty("systemProperty", "sysbar"); try { Message message = MessageBuilder.withPayload(new byte[0]).setHeader("sysbar", "foo").build(); - Object result = resolver.resolveArgument(paramSystemPropertyName, message); + MethodParameter param = this.resolvable.annot(header("#{systemProperties.systemProperty}")).arg(); + Object result = resolver.resolveArgument(param, message); assertEquals("foo", result); } finally { @@ -153,31 +136,22 @@ public class HeaderMethodArgumentResolverTests { @Test public void resolveOptionalHeaderWithValue() throws Exception { - GenericApplicationContext cxt = new GenericApplicationContext(); - cxt.refresh(); - - HeaderMethodArgumentResolver resolver = - new HeaderMethodArgumentResolver(new DefaultConversionService(), cxt.getBeanFactory()); - Message message = MessageBuilder.withPayload("foo").setHeader("foo", "bar").build(); - Object result = resolver.resolveArgument(paramOptional, message); + MethodParameter param = this.resolvable.annot(header("foo")).arg(Optional.class, String.class); + Object result = resolver.resolveArgument(param, message); assertEquals(Optional.of("bar"), result); } @Test public void resolveOptionalHeaderAsEmpty() throws Exception { - GenericApplicationContext cxt = new GenericApplicationContext(); - cxt.refresh(); - - HeaderMethodArgumentResolver resolver = - new HeaderMethodArgumentResolver(new DefaultConversionService(), cxt.getBeanFactory()); - Message message = MessageBuilder.withPayload("foo").build(); - Object result = resolver.resolveArgument(paramOptional, message); + MethodParameter param = this.resolvable.annot(header("foo")).arg(Optional.class, String.class); + Object result = resolver.resolveArgument(param, message); assertEquals(Optional.empty(), result); } + @SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"}) public void handleMessage( @Header String param1, @Header(name = "name", defaultValue = "bar") String param2, @@ -191,7 +165,7 @@ public class HeaderMethodArgumentResolverTests { public static class TestMessageHeaderAccessor extends NativeMessageHeaderAccessor { - protected TestMessageHeaderAccessor() { + TestMessageHeaderAccessor() { super((Map>) null); } } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolverTests.java index e666d507870..592a01e4da3 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-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. @@ -16,17 +16,16 @@ package org.springframework.messaging.handler.annotation.support; -import java.lang.reflect.Method; -import java.util.HashMap; +import java.util.Collections; import java.util.Map; -import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.handler.annotation.Headers; +import org.springframework.messaging.handler.invocation.ResolvableMethod; import org.springframework.messaging.support.MessageBuilder; import org.springframework.messaging.support.MessageHeaderAccessor; import org.springframework.messaging.support.NativeMessageHeaderAccessor; @@ -41,47 +40,31 @@ import static org.junit.Assert.*; */ public class HeadersMethodArgumentResolverTests { - private HeadersMethodArgumentResolver resolver; + private final HeadersMethodArgumentResolver resolver = new HeadersMethodArgumentResolver(); - private MethodParameter paramAnnotated; - private MethodParameter paramAnnotatedNotMap; - private MethodParameter paramMessageHeaders; - private MethodParameter paramMessageHeaderAccessor; - private MethodParameter paramMessageHeaderAccessorSubclass; + private Message message = + MessageBuilder.withPayload(new byte[0]).copyHeaders(Collections.singletonMap("foo", "bar")).build(); - private Message message; + private final ResolvableMethod resolvable = ResolvableMethod.on(getClass()).named("handleMessage").build(); - @Before - public void setup() throws Exception { - this.resolver = new HeadersMethodArgumentResolver(); - - Method method = getClass().getDeclaredMethod("handleMessage", Map.class, String.class, - MessageHeaders.class, MessageHeaderAccessor.class, TestMessageHeaderAccessor.class); - - this.paramAnnotated = new MethodParameter(method, 0); - this.paramAnnotatedNotMap = new MethodParameter(method, 1); - this.paramMessageHeaders = new MethodParameter(method, 2); - this.paramMessageHeaderAccessor = new MethodParameter(method, 3); - this.paramMessageHeaderAccessorSubclass = new MethodParameter(method, 4); - - Map headers = new HashMap<>(); - headers.put("foo", "bar"); - this.message = MessageBuilder.withPayload(new byte[0]).copyHeaders(headers).build(); - } - @Test public void supportsParameter() { - assertTrue(this.resolver.supportsParameter(this.paramAnnotated)); - assertFalse(this.resolver.supportsParameter(this.paramAnnotatedNotMap)); - assertTrue(this.resolver.supportsParameter(this.paramMessageHeaders)); - assertTrue(this.resolver.supportsParameter(this.paramMessageHeaderAccessor)); - assertTrue(this.resolver.supportsParameter(this.paramMessageHeaderAccessorSubclass)); + + assertTrue(this.resolver.supportsParameter( + this.resolvable.annotPresent(Headers.class).arg(Map.class, String.class, Object.class))); + + assertTrue(this.resolver.supportsParameter(this.resolvable.arg(MessageHeaders.class))); + assertTrue(this.resolver.supportsParameter(this.resolvable.arg(MessageHeaderAccessor.class))); + assertTrue(this.resolver.supportsParameter(this.resolvable.arg(TestMessageHeaderAccessor.class))); + + assertFalse(this.resolver.supportsParameter(this.resolvable.annotPresent(Headers.class).arg(String.class))); } @Test public void resolveArgumentAnnotated() throws Exception { - Object resolved = this.resolver.resolveArgument(this.paramAnnotated, this.message); + MethodParameter param = this.resolvable.annotPresent(Headers.class).arg(Map.class, String.class, Object.class); + Object resolved = this.resolver.resolveArgument(param, this.message); assertTrue(resolved instanceof Map); @SuppressWarnings("unchecked") @@ -91,12 +74,12 @@ public class HeadersMethodArgumentResolverTests { @Test(expected = IllegalStateException.class) public void resolveArgumentAnnotatedNotMap() throws Exception { - this.resolver.resolveArgument(this.paramAnnotatedNotMap, this.message); + this.resolver.resolveArgument(this.resolvable.annotPresent(Headers.class).arg(String.class), this.message); } @Test public void resolveArgumentMessageHeaders() throws Exception { - Object resolved = this.resolver.resolveArgument(this.paramMessageHeaders, this.message); + Object resolved = this.resolver.resolveArgument(this.resolvable.arg(MessageHeaders.class), this.message); assertTrue(resolved instanceof MessageHeaders); MessageHeaders headers = (MessageHeaders) resolved; @@ -105,7 +88,8 @@ public class HeadersMethodArgumentResolverTests { @Test public void resolveArgumentMessageHeaderAccessor() throws Exception { - Object resolved = this.resolver.resolveArgument(this.paramMessageHeaderAccessor, this.message); + MethodParameter param = this.resolvable.arg(MessageHeaderAccessor.class); + Object resolved = this.resolver.resolveArgument(param, this.message); assertTrue(resolved instanceof MessageHeaderAccessor); MessageHeaderAccessor headers = (MessageHeaderAccessor) resolved; @@ -114,7 +98,8 @@ public class HeadersMethodArgumentResolverTests { @Test public void resolveArgumentMessageHeaderAccessorSubclass() throws Exception { - Object resolved = this.resolver.resolveArgument(this.paramMessageHeaderAccessorSubclass, this.message); + MethodParameter param = this.resolvable.arg(TestMessageHeaderAccessor.class); + Object resolved = this.resolver.resolveArgument(param, this.message); assertTrue(resolved instanceof TestMessageHeaderAccessor); TestMessageHeaderAccessor headers = (TestMessageHeaderAccessor) resolved; @@ -124,7 +109,7 @@ public class HeadersMethodArgumentResolverTests { @SuppressWarnings("unused") private void handleMessage( - @Headers Map param1, + @Headers Map param1, @Headers String param2, MessageHeaders param3, MessageHeaderAccessor param4, @@ -134,7 +119,7 @@ public class HeadersMethodArgumentResolverTests { public static class TestMessageHeaderAccessor extends NativeMessageHeaderAccessor { - protected TestMessageHeaderAccessor(Message message) { + TestMessageHeaderAccessor(Message message) { super(message); }