diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/org.springframework.integration/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java
index bf7e45ede3..9fd4b80692 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java
@@ -36,7 +36,7 @@ import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
-import org.springframework.integration.message.MethodParameterMessageMapper;
+import org.springframework.integration.handler.MethodArgumentMessageMapper;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -225,7 +225,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory
private MessagingGateway createGatewayForMethod(Method method) throws Exception {
SimpleMessagingGateway gateway = new SimpleMessagingGateway(
- new MethodParameterMessageMapper(method), new SimpleMessageMapper());
+ new MethodArgumentMessageMapper(method), new SimpleMessageMapper());
if (this.getTaskScheduler() != null) {
gateway.setTaskScheduler(this.getTaskScheduler());
}
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageMappingMethodInvoker.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageMappingMethodInvoker.java
index 10bb0d0f1b..806923ab02 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageMappingMethodInvoker.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MessageMappingMethodInvoker.java
@@ -34,7 +34,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageHandlingException;
-import org.springframework.integration.message.MethodParameterMessageMapper;
import org.springframework.integration.util.DefaultMethodInvoker;
import org.springframework.integration.util.MethodInvoker;
import org.springframework.util.Assert;
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/MethodArgumentMessageMapper.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MethodArgumentMessageMapper.java
index 18b0a839ab..43d7755375 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/MethodArgumentMessageMapper.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MethodArgumentMessageMapper.java
@@ -16,43 +16,199 @@
package org.springframework.integration.handler;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import org.springframework.core.GenericTypeResolver;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.integration.annotation.Header;
+import org.springframework.integration.annotation.Headers;
import org.springframework.integration.core.Message;
-import org.springframework.integration.message.MethodParameterMessageMapper;
+import org.springframework.integration.core.MessageHeaders;
+import org.springframework.integration.message.InboundMessageMapper;
+import org.springframework.integration.message.MessageBuilder;
+import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.OutboundMessageMapper;
import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
/**
+ * A Message Mapper implementation that supports mapping from a Message
+ * to an argument array when invoking handler methods, and mapping to a
+ * Message from an argument array when invoking gateway methods.
+ *
+ * When mapping from a Message, the method parameters are matched
+ * against the Message, its payload as well as its headers. A message or
+ * payload parameter must not be annotated, and there can be at most one of
+ * these. In certain special cases, more than one non-annotated parameter can
+ * be used (more on this later), but there should always be at most one
+ * parameter that is expecting the message or its payload.
+ *
+ * If a method parameter is annotated with {@link Header @Header}, the
+ * annotation's value will be used as a header name. If such an annotation
+ * contains no value, then the parameter name will be used as long as the
+ * information is available in the class file (requires compilation with debug
+ * settings for parameter names).
+ *
+ * In addition a Map or Properties parameter can receive multiple message
+ * headers. In the case of a Map argument, all headers will be passed, but in
+ * the case of a Properties argument, only the headers with String-typed values
+ * will be passed. These parameters can be labeled explicitly with the
+ * {@link Headers @Headers} annotation, or matched implicitly by using a non-
+ * ambiguous method signature. There can be as many parameters annotated with
+ * @Header as necessary, but typically there should be only one parameter
+ * expecting multiple headers (with or without the @Headers annotation).
+ *
+ * If a Map or Properties object is expected, and the payload is not itself
+ * assignable to that type or capable of being converted to that type, then
+ * the MessageHeaders' values will be passed in the case of a Map-typed
+ * parameter, or the MessageHeaders' String-based values will be passed in the
+ * case of a Properties-typed parameter. In these cases multiple unannotated
+ * parameters are legal. If, however, the actual payload type is a Map or
+ * Properties instance, then this ambiguity cannot be resolved. For that
+ * reason, it is highly recommended to use the explicit
+ * {@link Headers @Headers} annotation whenever possible.
+ *
+ * Some examples of legal method signatures:
+ * public void dealWith(Object payload);
+ * public void dealWith(Message message);
+ * public void dealWith(@Header String myHeader, Object payload);
+ * public void dealWith(@Header String myHeader, @Header String anotherHeader);
+ *
+ * public void dealWith(@Headers Map headers, Object payload);
+ * public void dealWith(@Headers Properties headers, Map payload);
+ * public void dealWith(Properties headers, Object payload);
+ *
+ * Some examples of illegal method signatures:
+ * public void dealWith(Object payload, String payload);
+ * public void dealWith(Message message, Object payload);
+ * public void dealWith(Properties headers, Map payload);
+ *
* @author Mark Fisher
+ * @author Iwein Fuld
* @since 2.0
*/
-public class MethodArgumentMessageMapper implements OutboundMessageMapper {
+public class MethodArgumentMessageMapper implements InboundMessageMapper, OutboundMessageMapper {
private final Method method;
- //TODO: move core mapping logic from MethodParameterMessageMapper into this class
- private final MethodParameterMessageMapper innerMapper;
+ private final MethodParameterMetadata[] parameterMetadata;
+
+ private final MethodParameterMetadata payloadParameterMetadata;
+
+ private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
public MethodArgumentMessageMapper(Method method) {
Assert.notNull(method, "method must not be null");
this.method = method;
- this.innerMapper = new MethodParameterMessageMapper(method);
+ this.parameterMetadata = this.initializeParameterMetadata();
+ this.payloadParameterMetadata = getPayloadParameterFrom(this.parameterMetadata);
}
+ public Message> toMessage(Object[] parameters) {
+ Assert.isTrue(!ObjectUtils.isEmpty(parameters), "parameter array is required");
+ Assert.isTrue(parameters.length == this.parameterMetadata.length, "wrong number of parameters: expected "
+ + this.parameterMetadata.length + ", received " + parameters.length);
+ Message> message = null;
+ Object payload = null;
+ Map headers = new HashMap();
+ for (int i = 0; i < parameters.length; i++) {
+ Object value = parameters[i];
+ MethodParameterMetadata metadata = this.parameterMetadata[i];
+ Header headerAnnotation = metadata.getHeaderAnnotation();
+ if (metadata == payloadParameterMetadata) {
+ Assert.notNull(value, "payload object must not be null");
+ payload = value;
+ }
+ else if (headerAnnotation != null) {
+ String headerName = metadata.getHeaderName();
+ boolean required = headerAnnotation.required();
+ if (value != null) {
+ headers.put(headerName, value);
+ }
+ else {
+ Assert.isTrue(!required, "header '" + headerName + "' is required");
+ }
+ }
+ else if (metadata.hasHeadersAnnotation() || metadata.isMapOrProperties()) {
+ if (value != null) {
+ this.addHeadersAnnotatedParameterToMap(value, headers);
+ }
+ }
+ else {
+ Assert.isTrue(Message.class.isAssignableFrom(metadata.getParameterType()));
+ message = (Message>) value;
+ }
+ }
+ if (message != null) {
+ if (headers.isEmpty()) {
+ return message;
+ }
+ return MessageBuilder.fromMessage(message).copyHeadersIfAbsent(headers).build();
+ }
+ Assert.notNull(payload, "no parameter available for Message or payload");
+ return MessageBuilder.withPayload(payload).copyHeaders(headers).build();
+ }
public Object[] fromMessage(Message> message) throws Exception {
- Object args[] = null;
- Object mappingResult = this.innerMapper.fromMessage(message);
- if (mappingResult != null && mappingResult.getClass().isArray()
+ if (message == null) {
+ return null;
+ }
+
+ // TODO: allow null payload but return null above?
+ Assert.notNull(message.getPayload(), "Message payload must not be null.");
+
+ Object[] args = new Object[this.parameterMetadata.length];
+ for (int i = 0; i < this.parameterMetadata.length; i++) {
+ MethodParameterMetadata metadata = this.parameterMetadata[i];
+ Class> expectedType = metadata.getParameterType();
+ Header headerAnnotation = metadata.getHeaderAnnotation();
+ if (metadata == this.payloadParameterMetadata) {
+ args[i] = message.getPayload();
+ }
+ else if (headerAnnotation != null) {
+ String headerName = metadata.getHeaderName();
+ Object value = message.getHeaders().get(headerName);
+ if (value == null && headerAnnotation.required()) {
+ throw new MessageHandlingException(message, "required header '" + headerName + "' not available");
+ }
+ args[i] = value;
+ }
+ else if (metadata.isMapOrProperties()) {
+ if (Properties.class.isAssignableFrom(expectedType)) {
+ args[i] = this.getStringTypedHeaders(message);
+ }
+ else {
+ args[i] = message.getHeaders();
+ }
+ }
+ else {
+ Assert.isTrue(expectedType.isAssignableFrom(message.getClass())
+ && Message.class.isAssignableFrom(expectedType),
+ "Argument is neither header or payload, so it should be of type message.");
+ args[i] = message;
+ }
+ }
+
+ /*if (mappingResult != null && mappingResult.getClass().isArray()
&& (Object.class.isAssignableFrom(mappingResult.getClass().getComponentType()))) {
args = (Object[]) mappingResult;
}
else {
args = new Object[] { mappingResult };
}
+ */
+
if (args.length > 1 && message != null && message.getPayload() instanceof Map) {
int mapArgCount = 0;
boolean resolvedMapArg = false;
@@ -72,4 +228,139 @@ public class MethodArgumentMessageMapper implements OutboundMessageMapper message) {
+ Properties properties = new Properties();
+ MessageHeaders headers = message.getHeaders();
+ for (String key : headers.keySet()) {
+ Object value = headers.get(key);
+ if (value instanceof String) {
+ properties.setProperty(key, (String) value);
+ }
+ }
+ return properties;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void addHeadersAnnotatedParameterToMap(Object value, Map headers) {
+ Map map = (Map) value;
+ for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ Assert.isTrue(entry.getKey() instanceof String, "Map annotated with @Headers must have String-typed keys");
+ headers.put((String) entry.getKey(), entry.getValue());
+ }
+ }
+
+ private MethodParameterMetadata[] initializeParameterMetadata() {
+ Class>[] paramTypes = this.method.getParameterTypes();
+ MethodParameterMetadata[] parameterMetadata = new MethodParameterMetadata[paramTypes.length];
+ for (int i = 0; i < paramTypes.length; i++) {
+ MethodParameterMetadata metadata = new MethodParameterMetadata(this.method, i);
+ metadata.initParameterNameDiscovery(this.parameterNameDiscoverer);
+ GenericTypeResolver.resolveParameterType(metadata.parameter, this.method.getDeclaringClass());
+ parameterMetadata[i] = metadata;
+ }
+ return parameterMetadata;
+ }
+
+ private MethodParameterMetadata getPayloadParameterFrom(MethodParameterMetadata[] mpm) {
+ Set payloadCandidates = new HashSet();
+ int messageTypedParameterCount = 0;
+ for (MethodParameterMetadata metadata : mpm) {
+ if (Message.class.isAssignableFrom(metadata.getParameterType())) {
+ // expecting Message, not a payload candidate
+ messageTypedParameterCount++;
+ }
+ else if (metadata.getHeaderAnnotation() == null && !metadata.hasHeadersAnnotation()) {
+ // not expecting Message, and not explicitly annotated for headers
+ payloadCandidates.add(metadata);
+ }
+ }
+ if (payloadCandidates.size() > 1) {
+ Iterator iterator = payloadCandidates.iterator();
+ while (iterator.hasNext()) {
+ Class> type = iterator.next().getParameterType();
+ if (Map.class.isAssignableFrom(type)) {
+ // Map (or Properties) may accept headers rather than payload
+ iterator.remove();
+ }
+ }
+ }
+ if (payloadCandidates.size() + messageTypedParameterCount > 1) {
+ // too many candidates, create a helpful error message
+ int count = 0;
+ String[] candidateTypes = new String[payloadCandidates.size()];
+ for (MethodParameterMetadata candidate : payloadCandidates) {
+ candidateTypes[count++] = candidate.getParameterType().getName();
+ }
+ throw new IllegalArgumentException("At most one message or payload parameter " +
+ "is allowed on handler method [" + this.method.getName() +
+ "], but the following payload candidate types were found [" +
+ StringUtils.arrayToCommaDelimitedString(candidateTypes) +
+ "] and " + messageTypedParameterCount + " Message type(s).");
+ }
+ return (payloadCandidates.isEmpty() ? null : payloadCandidates.iterator().next());
+ }
+
+
+ private static class MethodParameterMetadata {
+
+ private final MethodParameter parameter;
+
+ private volatile Header _headerAnnotation;
+
+ private volatile boolean _hasHeadersAnnotation;
+
+ private MethodParameterMetadata(Method method, int index) {
+ this.parameter = new MethodParameter(method, index);
+ Annotation[] annotations = this.parameter.getParameterAnnotations();
+ for (Object o : annotations) {
+ if (o instanceof Header) {
+ this._headerAnnotation = (Header) o;
+ }
+ else if (Headers.class.isInstance(o)) {
+ Assert.isAssignable(Map.class, this.parameter.getParameterType(),
+ "parameter with the @Headers annotation must be assignable to java.util.Map");
+ this._hasHeadersAnnotation = true;
+ }
+ }
+ }
+
+ Header getHeaderAnnotation() {
+ return this._headerAnnotation;
+ }
+
+ boolean hasHeadersAnnotation() {
+ return this._hasHeadersAnnotation;
+ }
+
+ boolean isMapOrProperties() {
+ if (Properties.class.isAssignableFrom(this.parameter.getParameterType())
+ || Map.class.isAssignableFrom(this.parameter.getParameterType())) {
+ return true;
+ }
+ return false;
+ }
+
+ String getHeaderName() {
+ if (this.getHeaderAnnotation() == null) {
+ return null;
+ }
+ String paramName = this.getHeaderAnnotation().value();
+ if (!StringUtils.hasText(paramName)) {
+ paramName = this.parameter.getParameterName();
+ Assert.state(paramName != null,
+ "No parameter name specified on @Header and unable to discover in class file.");
+ }
+ return paramName;
+ }
+
+ private void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) {
+ this.parameter.initParameterNameDiscovery(parameterNameDiscoverer);
+ }
+
+ private Class> getParameterType() {
+ return this.parameter.getParameterType();
+ }
+ }
+
}
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/message/MethodParameterMessageMapper.java b/org.springframework.integration/src/main/java/org/springframework/integration/message/MethodParameterMessageMapper.java
deleted file mode 100644
index 1696dbc3df..0000000000
--- a/org.springframework.integration/src/main/java/org/springframework/integration/message/MethodParameterMessageMapper.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2002-2009 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.integration.message;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-import org.springframework.core.GenericTypeResolver;
-import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
-import org.springframework.core.MethodParameter;
-import org.springframework.core.ParameterNameDiscoverer;
-import org.springframework.integration.annotation.Header;
-import org.springframework.integration.annotation.Headers;
-import org.springframework.integration.core.Message;
-import org.springframework.integration.core.MessageHeaders;
-import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * Prepares arguments for handler methods. The method parameters are matched
- * against the Message, its payload as well as its headers. A message or
- * payload parameter must not be annotated, and there can be at most one of
- * these. In certain special cases, more than one non-annotated parameter can
- * be used (more on this later), but there should always be at most one
- * parameter that is expecting the message or its payload.
- *
- * If a method parameter is annotated with {@link Header @Header}, the
- * annotation's value will be used as a header name. If such an annotation
- * contains no value, then the parameter name will be used as long as the
- * information is available in the class file (requires compilation with debug
- * settings for parameter names).
- *
- * In addition a Map or Properties parameter can receive multiple message
- * headers. In the case of a Map argument, all headers will be passed, but in
- * the case of a Properties argument, only the headers with String-typed values
- * will be passed. These parameters can be labeled explicitly with the
- * {@link Headers @Headers} annotation, or matched implicitly by using a non-
- * ambiguous method signature. There can be as many parameters annotated with
- * @Header as necessary, but typically there should be only one parameter
- * expecting multiple headers (with or without the @Headers annotation).
- *
- * If a Map or Properties object is expected, and the payload is not itself
- * assignable to that type or capable of being converted to that type, then
- * the MessageHeaders' values will be passed in the case of a Map-typed
- * parameter, or the MessageHeaders' String-based values will be passed in the
- * case of a Properties-typed parameter. In these cases multiple unannotated
- * parameters are legal. If, however, the actual payload type is a Map or
- * Properties instance, then this ambiguity cannot be resolved. For that
- * reason, it is highly recommended to use the explicit
- * {@link Headers @Headers} annotation whenever possible.
- *
- * Some examples of legal method signatures:
- * public void dealWith(Object payload);
- * public void dealWith(Message message);
- * public void dealWith(@Header String myHeader, Object payload);
- * public void dealWith(@Header String myHeader, @Header String anotherHeader);
- *
- * public void dealWith(@Headers Map headers, Object payload);
- * public void dealWith(@Headers Properties headers, Map payload);
- * public void dealWith(Properties headers, Object payload);
- *
- * Some examples of illegal method signatures:
- * public void dealWith(Object payload, String payload);
- * public void dealWith(Message message, Object payload);
- * public void dealWith(Properties headers, Map payload);
- *
- *
- * @author Mark Fisher
- * @author Iwein Fuld
- */
-public class MethodParameterMessageMapper implements InboundMessageMapper, OutboundMessageMapper {
-
- private final Method method;
-
- private final MethodParameterMetadata[] parameterMetadata;
-
- private final MethodParameterMetadata payloadParameterMetadata;
-
- private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
-
-
- public MethodParameterMessageMapper(Method method) {
- Assert.notNull(method, "method must not be null");
- this.method = method;
- this.parameterMetadata = this.initializeParameterMetadata();
- this.payloadParameterMetadata = getPayloadParameterFrom(this.parameterMetadata);
- }
-
-
- private MethodParameterMetadata getPayloadParameterFrom(MethodParameterMetadata[] mpm) {
- Set payloadCandidates = new HashSet();
- int messageTypedParameterCount = 0;
- for (MethodParameterMetadata metadata : mpm) {
- if (Message.class.isAssignableFrom(metadata.getParameterType())) {
- // expecting Message, not a payload candidate
- messageTypedParameterCount++;
- }
- else if (metadata.getHeaderAnnotation() == null && !metadata.hasHeadersAnnotation()) {
- // not expecting Message, and not explicitly annotated for headers
- payloadCandidates.add(metadata);
- }
- }
- if (payloadCandidates.size() > 1) {
- Iterator iterator = payloadCandidates.iterator();
- while (iterator.hasNext()) {
- Class> type = iterator.next().getParameterType();
- if (Map.class.isAssignableFrom(type)) {
- // Map (or Properties) may accept headers rather than payload
- iterator.remove();
- }
- }
- }
- if (payloadCandidates.size() + messageTypedParameterCount > 1) {
- // too many candidates, create a helpful error message
- int count = 0;
- String[] candidateTypes = new String[payloadCandidates.size()];
- for (MethodParameterMetadata candidate : payloadCandidates) {
- candidateTypes[count++] = candidate.getParameterType().getName();
- }
- throw new IllegalArgumentException("At most one message or payload parameter " +
- "is allowed on handler method [" + this.method.getName() +
- "], but the following payload candidate types were found [" +
- StringUtils.arrayToCommaDelimitedString(candidateTypes) +
- "] and " + messageTypedParameterCount + " Message type(s).");
- }
- return (payloadCandidates.isEmpty() ? null : payloadCandidates.iterator().next());
- }
-
- private MethodParameterMetadata[] initializeParameterMetadata() {
- Class>[] paramTypes = this.method.getParameterTypes();
- MethodParameterMetadata[] parameterMetadata = new MethodParameterMetadata[paramTypes.length];
- for (int i = 0; i < paramTypes.length; i++) {
- MethodParameterMetadata metadata = new MethodParameterMetadata(this.method, i);
- metadata.initParameterNameDiscovery(this.parameterNameDiscoverer);
- GenericTypeResolver.resolveParameterType(metadata.parameter, this.method.getDeclaringClass());
- parameterMetadata[i] = metadata;
- }
- return parameterMetadata;
- }
-
- public Message> toMessage(Object[] parameters) {
- Assert.isTrue(!ObjectUtils.isEmpty(parameters), "parameter array is required");
- Assert.isTrue(parameters.length == this.parameterMetadata.length, "wrong number of parameters: expected "
- + this.parameterMetadata.length + ", received " + parameters.length);
- Message> message = null;
- Object payload = null;
- Map headers = new HashMap();
- for (int i = 0; i < parameters.length; i++) {
- Object value = parameters[i];
- MethodParameterMetadata metadata = this.parameterMetadata[i];
- Header headerAnnotation = metadata.getHeaderAnnotation();
- if (metadata == payloadParameterMetadata) {
- Assert.notNull(value, "payload object must not be null");
- payload = value;
- }
- else if (headerAnnotation != null) {
- String headerName = metadata.getHeaderName();
- boolean required = headerAnnotation.required();
- if (value != null) {
- headers.put(headerName, value);
- }
- else {
- Assert.isTrue(!required, "header '" + headerName + "' is required");
- }
- }
- else if (metadata.hasHeadersAnnotation() || metadata.isMapOrProperties()) {
- if (value != null) {
- this.addHeadersAnnotatedParameterToMap(value, headers);
- }
- }
- else {
- Assert.isTrue(Message.class.isAssignableFrom(metadata.getParameterType()));
- message = (Message>) value;
- }
- }
- if (message != null) {
- if (headers.isEmpty()) {
- return message;
- }
- return MessageBuilder.fromMessage(message).copyHeadersIfAbsent(headers).build();
- }
- Assert.notNull(payload, "no parameter available for Message or payload");
- return MessageBuilder.withPayload(payload).copyHeaders(headers).build();
- }
-
- public Object[] fromMessage(Message> message) {
- if (message == null) {
- return null;
- }
- Assert.notNull(message.getPayload(), "Message payload must not be null.");
- Object[] args = new Object[this.parameterMetadata.length];
- for (int i = 0; i < this.parameterMetadata.length; i++) {
- MethodParameterMetadata metadata = this.parameterMetadata[i];
- Class> expectedType = metadata.getParameterType();
- Header headerAnnotation = metadata.getHeaderAnnotation();
- if (metadata == this.payloadParameterMetadata) {
- args[i] = message.getPayload();
- }
- else if (headerAnnotation != null) {
- String headerName = metadata.getHeaderName();
- Object value = message.getHeaders().get(headerName);
- if (value == null && headerAnnotation.required()) {
- throw new MessageHandlingException(message, "required header '" + headerName + "' not available");
- }
- args[i] = value;
- }
- else if (metadata.isMapOrProperties()) {
- if (Properties.class.isAssignableFrom(expectedType)) {
- args[i] = this.getStringTypedHeaders(message);
- }
- else {
- args[i] = message.getHeaders();
- }
- }
- else {
- Assert.isTrue(expectedType.isAssignableFrom(message.getClass())
- && Message.class.isAssignableFrom(expectedType),
- "Argument is neither header or payload, so it should be of type message.");
- args[i] = message;
- }
- }
- return args;
- }
-
- private Properties getStringTypedHeaders(Message> message) {
- Properties properties = new Properties();
- MessageHeaders headers = message.getHeaders();
- for (String key : headers.keySet()) {
- Object value = headers.get(key);
- if (value instanceof String) {
- properties.setProperty(key, (String) value);
- }
- }
- return properties;
- }
-
- @SuppressWarnings("unchecked")
- private void addHeadersAnnotatedParameterToMap(Object value, Map headers) {
- Map map = (Map) value;
- for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
- Map.Entry entry = (Map.Entry) iter.next();
- Assert.isTrue(entry.getKey() instanceof String, "Map annotated with @Headers must have String-typed keys");
- headers.put((String) entry.getKey(), entry.getValue());
- }
- }
-
- private static class MethodParameterMetadata {
-
- private final MethodParameter parameter;
-
- private volatile Header _headerAnnotation;
-
- private volatile boolean _hasHeadersAnnotation;
-
- private MethodParameterMetadata(Method method, int index) {
- this.parameter = new MethodParameter(method, index);
- Annotation[] annotations = this.parameter.getParameterAnnotations();
- for (Object o : annotations) {
- if (o instanceof Header) {
- this._headerAnnotation = (Header) o;
- }
- else if (Headers.class.isInstance(o)) {
- Assert.isAssignable(Map.class, this.parameter.getParameterType(),
- "parameter with the @Headers annotation must be assignable to java.util.Map");
- this._hasHeadersAnnotation = true;
- }
- }
- }
-
- Header getHeaderAnnotation() {
- return this._headerAnnotation;
- }
-
- boolean hasHeadersAnnotation() {
- return this._hasHeadersAnnotation;
- }
-
- boolean isMapOrProperties() {
- if (Properties.class.isAssignableFrom(this.parameter.getParameterType())
- || Map.class.isAssignableFrom(this.parameter.getParameterType())) {
- return true;
- }
- return false;
- }
-
- String getHeaderName() {
- if (this.getHeaderAnnotation() == null) {
- return null;
- }
- String paramName = this.getHeaderAnnotation().value();
- if (!StringUtils.hasText(paramName)) {
- paramName = this.parameter.getParameterName();
- Assert.state(paramName != null,
- "No parameter name specified on @Header and unable to discover in class file.");
- }
- return paramName;
- }
-
- private void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) {
- this.parameter.initParameterNameDiscovery(parameterNameDiscoverer);
- }
-
- private Class> getParameterType() {
- return this.parameter.getParameterType();
- }
- }
-
-}
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java
index 6da9f7a541..5892ba89bd 100644
--- a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java
@@ -28,6 +28,7 @@ import org.junit.Test;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.Headers;
import org.springframework.integration.core.Message;
+import org.springframework.integration.handler.MethodArgumentMessageMapper;
/**
* @author Mark Fisher
@@ -38,7 +39,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithOptionalHeader() throws Exception {
Method method = TestService.class.getMethod("optionalHeader", Integer.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Object[] args = mapper.fromMessage(new StringMessage("foo"));
assertEquals(1, args.length);
assertNull(args[0]);
@@ -47,14 +48,14 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test(expected = MessageHandlingException.class)
public void fromMessageWithRequiredHeaderNotProvided() throws Exception {
Method method = TestService.class.getMethod("requiredHeader", Integer.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
mapper.fromMessage(new StringMessage("foo"));
}
@Test
public void fromMessageWithRequiredHeaderProvided() throws Exception {
Method method = TestService.class.getMethod("requiredHeader", Integer.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("foo")
.setHeader("num", new Integer(123)).build();
Object[] args = mapper.fromMessage(message);
@@ -65,7 +66,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test(expected = MessageHandlingException.class)
public void fromMessageWithOptionalAndRequiredHeaderAndOnlyOptionalHeaderProvided() throws Exception {
Method method = TestService.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("foo")
.setHeader("prop", "bar").build();
mapper.fromMessage(message);
@@ -74,7 +75,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithOptionalAndRequiredHeaderAndOnlyRequiredHeaderProvided() throws Exception {
Method method = TestService.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("foo")
.setHeader("num", new Integer(123)).build();
Object[] args = mapper.fromMessage(message);
@@ -86,7 +87,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithOptionalAndRequiredHeaderAndBothHeadersProvided() throws Exception {
Method method = TestService.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("foo")
.setHeader("num", new Integer(123))
.setHeader("prop", "bar")
@@ -100,7 +101,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithPropertiesMethodAndHeadersAnnotation() throws Exception {
Method method = TestService.class.getMethod("propertiesHeaders", Properties.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("test")
.setHeader("prop1", "foo").setHeader("prop2", "bar").build();
Object[] args = mapper.fromMessage(message);
@@ -113,7 +114,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithPropertiesAndObjectMethod() throws Exception {
Method method = TestService.class.getMethod("propertiesHeadersAndPayload", Properties.class, Object.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("test")
.setHeader("prop1", "foo").setHeader("prop2", "bar").build();
Object[] args = mapper.fromMessage(message);
@@ -128,7 +129,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithMapAndObjectMethod() throws Exception {
Method method = TestService.class.getMethod("mapHeadersAndPayload", Map.class, Object.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("test")
.setHeader("prop1", "foo").setHeader("prop2", "bar").build();
Object[] args = mapper.fromMessage(message);
@@ -143,7 +144,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@Test
public void fromMessageWithPropertiesMethodAndPropertiesPayload() throws Exception {
Method method = TestService.class.getMethod("propertiesPayload", Properties.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Properties payload = new Properties();
payload.setProperty("prop1", "foo");
payload.setProperty("prop2", "bar");
@@ -160,7 +161,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@SuppressWarnings("unchecked")
public void fromMessageWithMapMethodAndHeadersAnnotation() throws Exception {
Method method = TestService.class.getMethod("mapHeaders", Map.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message message = MessageBuilder.withPayload("test")
.setHeader("attrib1", new Integer(123))
.setHeader("attrib2", new Integer(456)).build();
@@ -174,7 +175,7 @@ public class MethodParameterMessageMapperFromMessageTests {
@SuppressWarnings("unchecked")
public void fromMessageWithMapMethodAndMapPayload() throws Exception {
Method method = TestService.class.getMethod("mapPayload", Map.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Map payload = new HashMap();
payload.put("attrib1", new Integer(88));
payload.put("attrib2", new Integer(99));
@@ -189,6 +190,7 @@ public class MethodParameterMessageMapperFromMessageTests {
}
+ @SuppressWarnings("unused")
private static class TestService {
public String messageOnly(Message> message) {
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperInitializationTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperInitializationTests.java
index bc48d454ce..86c1b7b153 100644
--- a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperInitializationTests.java
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperInitializationTests.java
@@ -19,8 +19,8 @@ package org.springframework.integration.message;
import java.lang.reflect.Method;
import org.junit.Test;
-
import org.springframework.integration.core.Message;
+import org.springframework.integration.handler.MethodArgumentMessageMapper;
/**
* @author Mark Fisher
@@ -30,19 +30,19 @@ public class MethodParameterMessageMapperInitializationTests {
@Test(expected = IllegalArgumentException.class)
public void messageAndPayload() throws Exception {
Method method = TestService.class.getMethod("messageAndPayload", Message.class, String.class);
- new MethodParameterMessageMapper(method);
+ new MethodArgumentMessageMapper(method);
}
@Test(expected = IllegalArgumentException.class)
public void twoMessages() throws Exception {
Method method = TestService.class.getMethod("twoMessages", Message.class, Message.class);
- new MethodParameterMessageMapper(method);
+ new MethodArgumentMessageMapper(method);
}
@Test(expected = IllegalArgumentException.class)
public void twoPayloads() throws Exception {
Method method = TestService.class.getMethod("twoPayloads", String.class, String.class);
- new MethodParameterMessageMapper(method);
+ new MethodArgumentMessageMapper(method);
}
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperToMessageTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperToMessageTests.java
index d9410f12a4..baa2dae8ce 100644
--- a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperToMessageTests.java
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperToMessageTests.java
@@ -28,6 +28,7 @@ import org.junit.Test;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.Headers;
import org.springframework.integration.core.Message;
+import org.springframework.integration.handler.MethodArgumentMessageMapper;
/**
* @author Mark Fisher
@@ -37,7 +38,7 @@ public class MethodParameterMessageMapperToMessageTests {
@Test
public void toMessageWithPayload() throws Exception {
Method method = TestService.class.getMethod("sendPayload", String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> message = mapper.toMessage(new Object[] { "test" });
assertEquals("test", message.getPayload());
}
@@ -45,14 +46,14 @@ public class MethodParameterMessageMapperToMessageTests {
@Test(expected = IllegalArgumentException.class)
public void toMessageWithTooManyParameters() throws Exception {
Method method = TestService.class.getMethod("sendPayload", String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
mapper.toMessage(new Object[] { "test" , "oops" });
}
@Test(expected = IllegalArgumentException.class)
public void toMessageWithEmptyParameterArray() throws Exception {
Method method = TestService.class.getMethod("sendPayload", String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
mapper.toMessage(new Object[] {});
}
@@ -60,7 +61,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndHeader() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeader", String.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> message = mapper.toMessage(new Object[] { "test", "bar" });
assertEquals("test", message.getPayload());
assertEquals("bar", message.getHeaders().get("foo"));
@@ -70,7 +71,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndRequiredHeaderButNullValue() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeader", String.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
mapper.toMessage(new Object[] { "test", null });
}
@@ -78,7 +79,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndOptionalHeaderWithValueProvided() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndOptionalHeader", String.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> message = mapper.toMessage(new Object[] { "test", "bar" });
assertEquals("test", message.getPayload());
assertEquals("bar", message.getHeaders().get("foo"));
@@ -88,7 +89,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndOptionalHeaderWithNullValue() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndOptionalHeader", String.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> message = mapper.toMessage(new Object[] { "test", null });
assertEquals("test", message.getPayload());
assertNull(message.getHeaders().get("foo"));
@@ -98,7 +99,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndHeadersMap() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeadersMap", String.class, Map.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Map headers = new HashMap();
headers.put("abc", 123);
headers.put("def", 456);
@@ -112,7 +113,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndNullHeadersMap() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeadersMap", String.class, Map.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> message = mapper.toMessage(new Object[] { "test", null });
assertEquals("test", message.getPayload());
}
@@ -121,7 +122,7 @@ public class MethodParameterMessageMapperToMessageTests {
public void toMessageWithPayloadAndHeadersMapWithNonStringKey() throws Exception {
Method method = TestService.class.getMethod(
"sendPayloadAndHeadersMap", String.class, Map.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Map headers = new HashMap();
headers.put(123, "abc");
mapper.toMessage(new Object[] { "test", headers });
@@ -130,7 +131,7 @@ public class MethodParameterMessageMapperToMessageTests {
@Test
public void toMessageWithMessageParameter() throws Exception {
Method method = TestService.class.getMethod("sendMessage", Message.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> inputMessage = MessageBuilder.withPayload("test message").build();
Message> message = mapper.toMessage(new Object[] { inputMessage });
assertEquals("test message", message.getPayload());
@@ -139,7 +140,7 @@ public class MethodParameterMessageMapperToMessageTests {
@Test
public void toMessageWithMessageParameterAndHeader() throws Exception {
Method method = TestService.class.getMethod("sendMessageAndHeader", Message.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> inputMessage = MessageBuilder.withPayload("test message").build();
Message> message = mapper.toMessage(new Object[] { inputMessage, "bar" });
assertEquals("test message", message.getPayload());
@@ -149,7 +150,7 @@ public class MethodParameterMessageMapperToMessageTests {
@Test(expected = IllegalArgumentException.class)
public void toMessageWithMessageParameterAndRequiredHeaderButNullValue() throws Exception {
Method method = TestService.class.getMethod("sendMessageAndHeader", Message.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> inputMessage = MessageBuilder.withPayload("test message").build();
mapper.toMessage(new Object[] { inputMessage, null });
}
@@ -157,7 +158,7 @@ public class MethodParameterMessageMapperToMessageTests {
@Test
public void toMessageWithMessageParameterAndOptionalHeaderWithValue() throws Exception {
Method method = TestService.class.getMethod("sendMessageAndOptionalHeader", Message.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> inputMessage = MessageBuilder.withPayload("test message").build();
Message> message = mapper.toMessage(new Object[] { inputMessage, "bar" });
assertEquals("test message", message.getPayload());
@@ -167,7 +168,7 @@ public class MethodParameterMessageMapperToMessageTests {
@Test
public void toMessageWithMessageParameterAndOptionalHeaderWithNull() throws Exception {
Method method = TestService.class.getMethod("sendMessageAndOptionalHeader", Message.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
Message> inputMessage = MessageBuilder.withPayload("test message").build();
Message> message = mapper.toMessage(new Object[] { inputMessage, null });
assertEquals("test message", message.getPayload());
@@ -177,14 +178,14 @@ public class MethodParameterMessageMapperToMessageTests {
@Test(expected = IllegalArgumentException.class)
public void noArgs() throws Exception {
Method method = TestService.class.getMethod("noArgs", new Class>[] {});
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
mapper.toMessage(new Object[] {});
}
@Test(expected = IllegalArgumentException.class)
public void onlyHeaders() throws Exception {
Method method = TestService.class.getMethod("onlyHeaders", String.class, String.class);
- MethodParameterMessageMapper mapper = new MethodParameterMessageMapper(method);
+ MethodArgumentMessageMapper mapper = new MethodArgumentMessageMapper(method);
mapper.toMessage(new Object[] { "abc", "def" });
}