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:
- *
- * - Obtain named value information for a method parameter
- *
- Resolve names into argument values
- *
- Handle missing argument values when argument values are required
- *
- Optionally handle a resolved value
- *
+ * 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:
*
- * - Parameters assignable to {@link Map} annotated with {@link Headers @Headers}
- *
- Parameters of type {@link MessageHeaders}
- *
- Parameters assignable to {@link MessageHeaderAccessor}
+ *
- {@link Headers @Headers} {@link Map}
+ *
- {@link MessageHeaders}
+ *
- {@link MessageHeaderAccessor}
*
*
* @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);
}