Browse Source

Polish

Updates to synchronize with newly created reactive equivalents.
pull/22513/head
Rossen Stoyanchev 7 years ago
parent
commit
ceccd9fbee
  1. 79
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java
  2. 30
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java
  3. 20
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolver.java
  4. 18
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolver.java
  5. 44
      spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java
  6. 82
      spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java
  7. 65
      spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolverTests.java

79
spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AbstractNamedValueMethodArgumentResolver.java

@ -33,24 +33,20 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes @@ -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.
*
* <p>Subclasses define how to do the following:
* <ul>
* <li>Obtain named value information for a method parameter
* <li>Resolve names into argument values
* <li>Handle missing argument values when argument values are required
* <li>Optionally handle a resolved value
* </ul>
* <p>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.
*
* <p>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.
* <p>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.
*
* <p>A {@link ConversionService} may be used to apply type conversion to the resolved
* argument value if it doesn't match the method parameter type.
* <p>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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 {

30
spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java

@ -23,22 +23,20 @@ import org.springframework.core.convert.ConversionService; @@ -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 @@ -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<String, String> vars =
(Map<String, String>) 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<String, String> vars = (Map<String, String>) 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() + "]");
}

20
spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolver.java

@ -33,10 +33,15 @@ import org.springframework.messaging.support.NativeMessageHeaderAccessor; @@ -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 @@ -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 @@ -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.");
}
}

18
spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolver.java

@ -1,5 +1,5 @@ @@ -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; @@ -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:
* <ul>
* <li>Parameters assignable to {@link Map} annotated with {@link Headers @Headers}
* <li>Parameters of type {@link MessageHeaders}
* <li>Parameters assignable to {@link MessageHeaderAccessor}
* <li>{@link Headers @Headers} {@link Map}
* <li>{@link MessageHeaders}
* <li>{@link MessageHeaderAccessor}
* </ul>
*
* @author Rossen Stoyanchev
@ -58,7 +57,7 @@ public class HeadersMethodArgumentResolver implements HandlerMethodArgumentResol @@ -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 @@ -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() + ". ");
}
}

44
spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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.*; @@ -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 { @@ -80,17 +62,19 @@ public class DestinationVariableMethodArgumentResolverTests {
Message<byte[]> 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<byte[]> 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")

82
spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeaderMethodArgumentResolverTests.java

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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; @@ -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 { @@ -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<byte[]> 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 { @@ -98,7 +76,7 @@ public class HeaderMethodArgumentResolverTests {
TestMessageHeaderAccessor headers = new TestMessageHeaderAccessor();
headers.setNativeHeader("param1", "foo");
Message<byte[]> 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 { @@ -108,20 +86,23 @@ public class HeaderMethodArgumentResolverTests {
headers.setNativeHeader("param1", "native-foo");
Message<byte[]> 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<byte[]> 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<byte[]> 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 { @@ -130,7 +111,8 @@ public class HeaderMethodArgumentResolverTests {
System.setProperty("systemProperty", "sysbar");
try {
Message<byte[]> 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 { @@ -143,7 +125,8 @@ public class HeaderMethodArgumentResolverTests {
System.setProperty("systemProperty", "sysbar");
try {
Message<byte[]> 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 { @@ -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<String> 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<String> 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 { @@ -191,7 +165,7 @@ public class HeaderMethodArgumentResolverTests {
public static class TestMessageHeaderAccessor extends NativeMessageHeaderAccessor {
protected TestMessageHeaderAccessor() {
TestMessageHeaderAccessor() {
super((Map<String, List<String>>) null);
}
}

65
spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/HeadersMethodArgumentResolverTests.java

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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.*; @@ -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<byte[]> message =
MessageBuilder.withPayload(new byte[0]).copyHeaders(Collections.singletonMap("foo", "bar")).build();
private Message<byte[]> 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);
@Test
public void supportsParameter() {
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);
assertTrue(this.resolver.supportsParameter(
this.resolvable.annotPresent(Headers.class).arg(Map.class, String.class, Object.class)));
Map<String, Object> headers = new HashMap<>();
headers.put("foo", "bar");
this.message = MessageBuilder.withPayload(new byte[0]).copyHeaders(headers).build();
}
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)));
@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));
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 { @@ -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 { @@ -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 { @@ -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 { @@ -124,7 +109,7 @@ public class HeadersMethodArgumentResolverTests {
@SuppressWarnings("unused")
private void handleMessage(
@Headers Map<String, ?> param1,
@Headers Map<String, Object> param1,
@Headers String param2,
MessageHeaders param3,
MessageHeaderAccessor param4,
@ -134,7 +119,7 @@ public class HeadersMethodArgumentResolverTests { @@ -134,7 +119,7 @@ public class HeadersMethodArgumentResolverTests {
public static class TestMessageHeaderAccessor extends NativeMessageHeaderAccessor {
protected TestMessageHeaderAccessor(Message<?> message) {
TestMessageHeaderAccessor(Message<?> message) {
super(message);
}

Loading…
Cancel
Save