The @Headers annotation is now required (for clarity) when mapping from a Message to a parameter intending to receive MessageHeaders. If the expected payload type is a Map or Properties object, it can still be mapped to any non-annotated parameter of that same type.
This commit is contained in:
@@ -75,21 +75,23 @@ public class MethodParameterMessageMapper implements MessageMapper<Object[]> {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
Object value = parameters[i];
|
||||
MethodParameterMetadata metadata = this.parameterMetadata[i];
|
||||
Class<?> expectedType = metadata.type;
|
||||
if (expectedType.equals(Header.class)) {
|
||||
Header headerAnnotation = metadata.getHeaderAnnotation();
|
||||
if (headerAnnotation != null) {
|
||||
String headerName = this.resolveHeaderName(headerAnnotation, metadata);
|
||||
boolean required = headerAnnotation.required();
|
||||
if (value != null) {
|
||||
headers.put(metadata.key, value);
|
||||
headers.put(headerName, value);
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(!metadata.required, "header '" + metadata.key + "' is required");
|
||||
Assert.isTrue(!required, "header '" + headerName + "' is required");
|
||||
}
|
||||
}
|
||||
else if (expectedType.equals(Headers.class)) {
|
||||
else if (metadata.hasHeadersAnnotation()) {
|
||||
if (value != null) {
|
||||
this.addHeadersAnnotatedParameterToMap(value, headers);
|
||||
}
|
||||
}
|
||||
else if (expectedType.equals(Message.class)) {
|
||||
else if (metadata.getParameterType().equals(Message.class)) {
|
||||
message = (Message<?>) value;
|
||||
}
|
||||
else {
|
||||
@@ -115,27 +117,28 @@ public class MethodParameterMessageMapper implements MessageMapper<Object[]> {
|
||||
Object[] args = new Object[this.parameterMetadata.length];
|
||||
for (int i = 0; i < this.parameterMetadata.length; i++) {
|
||||
MethodParameterMetadata metadata = this.parameterMetadata[i];
|
||||
Class<?> expectedType = metadata.type;
|
||||
if (expectedType.equals(Header.class)) {
|
||||
Object value = message.getHeaders().get(metadata.key);
|
||||
if (value == null && metadata.required) {
|
||||
Class<?> expectedType = metadata.getParameterType();
|
||||
Header headerAnnotation = metadata.getHeaderAnnotation();
|
||||
if (headerAnnotation != null) {
|
||||
String headerName = this.resolveHeaderName(headerAnnotation, metadata);
|
||||
Object value = message.getHeaders().get(headerName);
|
||||
if (value == null && headerAnnotation.required()) {
|
||||
throw new MessageHandlingException(message,
|
||||
"required header '" + metadata.key + "' not available");
|
||||
"required header '" + headerName + "' not available");
|
||||
}
|
||||
args[i] = value;
|
||||
}
|
||||
else if (metadata.hasHeadersAnnotation()) {
|
||||
if (Properties.class.isAssignableFrom(expectedType)) {
|
||||
args[i] = this.getStringTypedHeaders(message);
|
||||
}
|
||||
else {
|
||||
args[i] = message.getHeaders();
|
||||
}
|
||||
}
|
||||
else if (expectedType.isAssignableFrom(message.getClass())) {
|
||||
args[i] = message;
|
||||
}
|
||||
else if (expectedType.isAssignableFrom(message.getPayload().getClass())) {
|
||||
args[i] = message.getPayload();
|
||||
}
|
||||
else if (expectedType.equals(Map.class)) {
|
||||
args[i] = message.getHeaders();
|
||||
}
|
||||
else if (expectedType.equals(Properties.class)) {
|
||||
args[i] = this.getStringTypedHeaders(message);
|
||||
}
|
||||
else {
|
||||
args[i] = message.getPayload();
|
||||
}
|
||||
@@ -148,28 +151,15 @@ public class MethodParameterMessageMapper implements MessageMapper<Object[]> {
|
||||
Class<?>[] paramTypes = this.method.getParameterTypes();
|
||||
this.parameterMetadata = new MethodParameterMetadata[paramTypes.length];
|
||||
for (int i = 0; i < parameterMetadata.length; i++) {
|
||||
MethodParameter methodParam = new MethodParameter(this.method, i);
|
||||
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, this.method.getDeclaringClass());
|
||||
Object[] paramAnnotations = methodParam.getParameterAnnotations();
|
||||
for (int j = 0; j < paramAnnotations.length; j++) {
|
||||
if (Header.class.isInstance(paramAnnotations[j])) {
|
||||
Header headerAnnotation = (Header) paramAnnotations[j];
|
||||
String headerName = this.resolveHeaderName(headerAnnotation, methodParam);
|
||||
parameterMetadata[i] = new MethodParameterMetadata(Header.class, headerName, headerAnnotation.required());
|
||||
}
|
||||
else if (Headers.class.isInstance(paramAnnotations[j])) {
|
||||
Assert.isAssignable(Map.class, methodParam.getParameterType(),
|
||||
"parameter with the @Headers annotation must be assignable to java.util.Map");
|
||||
parameterMetadata[i] = new MethodParameterMetadata(Headers.class, null, false);
|
||||
}
|
||||
}
|
||||
if (parameterMetadata[i] == null) {
|
||||
MethodParameterMetadata metadata = new MethodParameterMetadata(this.method, i);
|
||||
metadata.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||
GenericTypeResolver.resolveParameterType(metadata, this.method.getDeclaringClass());
|
||||
if (metadata.getHeaderAnnotation() == null && !metadata.hasHeadersAnnotation()) {
|
||||
// this is either a Message or the Object to be used as a Message payload
|
||||
Assert.isTrue(!foundMessageOrPayload, "only one Message or payload parameter is allowed");
|
||||
foundMessageOrPayload = true;
|
||||
parameterMetadata[i] = new MethodParameterMetadata(methodParam.getParameterType(), null, false);
|
||||
}
|
||||
parameterMetadata[i] = metadata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,21 +196,50 @@ public class MethodParameterMessageMapper implements MessageMapper<Object[]> {
|
||||
}
|
||||
|
||||
|
||||
private static class MethodParameterMetadata {
|
||||
private static class MethodParameterMetadata extends MethodParameter {
|
||||
|
||||
private final Class<?> type;
|
||||
private volatile Header _headerAnnotation;
|
||||
|
||||
private final String key;
|
||||
|
||||
private final boolean required;
|
||||
private volatile boolean _hasHeadersAnnotation;
|
||||
|
||||
|
||||
MethodParameterMetadata(Class<?> type, String key, boolean required) {
|
||||
this.type = type;
|
||||
this.key = key;
|
||||
this.required = required;
|
||||
private MethodParameterMetadata(Method method, int index) {
|
||||
super(method, index);
|
||||
}
|
||||
|
||||
public Header getHeaderAnnotation() {
|
||||
if (this._headerAnnotation != null) {
|
||||
return this._headerAnnotation;
|
||||
}
|
||||
if (this.getParameterAnnotations() == null) {
|
||||
return null;
|
||||
}
|
||||
for (Object o : this.getParameterAnnotations()) {
|
||||
if (o instanceof Header) {
|
||||
this._headerAnnotation = (Header) o;
|
||||
return this._headerAnnotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasHeadersAnnotation() {
|
||||
if (this._hasHeadersAnnotation) {
|
||||
return true;
|
||||
}
|
||||
if (this.getParameterAnnotations() == null) {
|
||||
return false;
|
||||
}
|
||||
for (Object o : this.getParameterAnnotations()) {
|
||||
if (Headers.class.isInstance(o)) {
|
||||
Assert.isAssignable(Map.class, this.getParameterType(),
|
||||
"parameter with the @Headers annotation must be assignable to java.util.Map");
|
||||
}
|
||||
this._hasHeadersAnnotation = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@ import java.util.Properties;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.annotation.Header;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MethodParameterMessageMapper;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.integration.annotation.Headers;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -101,8 +97,8 @@ public class MethodParameterMessageMapperFromMessageTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromMessageWithPropertiesMethodAndNonPropertiesPayload() throws Exception {
|
||||
Method method = TestService.class.getMethod("propertiesMethod", Properties.class);
|
||||
public void fromMessageWithPropertiesMethodAndHeadersAnnotation() throws Exception {
|
||||
Method method = TestService.class.getMethod("propertiesHeaders", Properties.class);
|
||||
MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
|
||||
Message<String> message = MessageBuilder.withPayload("test")
|
||||
.setHeader("prop1", "foo").setHeader("prop2", "bar").build();
|
||||
@@ -115,7 +111,7 @@ public class MethodParameterMessageMapperFromMessageTests {
|
||||
|
||||
@Test
|
||||
public void fromMessageWithPropertiesMethodAndPropertiesPayload() throws Exception {
|
||||
Method method = TestService.class.getMethod("propertiesMethod", Properties.class);
|
||||
Method method = TestService.class.getMethod("propertiesPayload", Properties.class);
|
||||
MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
|
||||
Properties payload = new Properties();
|
||||
payload.setProperty("prop1", "foo");
|
||||
@@ -131,8 +127,8 @@ public class MethodParameterMessageMapperFromMessageTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void fromMessageWithMapMethodAndNonMapPayload() throws Exception {
|
||||
Method method = TestService.class.getMethod("mapMethod", Map.class);
|
||||
public void fromMessageWithMapMethodAndHeadersAnnotation() throws Exception {
|
||||
Method method = TestService.class.getMethod("mapHeaders", Map.class);
|
||||
MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
|
||||
Message<String> message = MessageBuilder.withPayload("test")
|
||||
.setHeader("attrib1", new Integer(123))
|
||||
@@ -146,7 +142,7 @@ public class MethodParameterMessageMapperFromMessageTests {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void fromMessageWithMapMethodAndMapPayload() throws Exception {
|
||||
Method method = TestService.class.getMethod("mapMethod", Map.class);
|
||||
Method method = TestService.class.getMethod("mapPayload", Map.class);
|
||||
MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
|
||||
Map<String, Integer> payload = new HashMap<String, Integer>();
|
||||
payload.put("attrib1", new Integer(123));
|
||||
@@ -188,12 +184,21 @@ public class MethodParameterMessageMapperFromMessageTests {
|
||||
return prop + num;
|
||||
}
|
||||
|
||||
public Properties propertiesMethod(Properties properties) {
|
||||
public Properties propertiesPayload(Properties properties) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public Properties propertiesHeaders(@Headers Properties properties) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map mapMethod(Map map) {
|
||||
public Map mapPayload(Map map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map mapHeaders(@Headers Map map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user