Extracted message-to-args mapping logic from AbstractMessageHandler to MethodArgumentMessageMapper. Defined a separate abstract method in AbstractMessageHandler for post-processing a return value that is already a Message. DefaultMethodInvoker catches an IllegalArgumentException in case the Method instance no longer matches after a Proxy and "resets" the correct Method if it can be determined from the 'methodName' property. Replaced AnnotationMethodTransformerAdapter with TransformerMessageHandler.

This commit is contained in:
Mark Fisher
2008-08-13 23:31:18 +00:00
parent 0f93cab8cc
commit 0d49689821
19 changed files with 580 additions and 644 deletions

View File

@@ -29,7 +29,7 @@ import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
import org.springframework.integration.handler.DefaultMessageHandler;
import org.springframework.integration.handler.MessageHandlerChain;
import org.springframework.util.StringUtils;
@@ -81,6 +81,7 @@ public class HandlerParser implements BeanDefinitionParser {
return beanDefinition;
}
@SuppressWarnings("unchecked")
private BeanDefinition parseHandler(Element element, ParserContext parserContext, ManagedList handlers) {
boolean isInnerHandler = (handlers != null);
String ref = element.getAttribute("ref");
@@ -113,15 +114,15 @@ public class HandlerParser implements BeanDefinitionParser {
}
private BeanDefinitionHolder parseHandlerAdapter(String id, String handlerRef, String handlerMethod, ParserContext parserContext, boolean isInnerHandler) {
BeanDefinition handlerAdapterDef = new RootBeanDefinition(DefaultMessageHandlerAdapter.class);
handlerAdapterDef.getPropertyValues().addPropertyValue(OBJECT_PROPERTY, new RuntimeBeanReference(handlerRef));
handlerAdapterDef.getPropertyValues().addPropertyValue(METHOD_NAME_PROPERTY, handlerMethod);
String adapterBeanName = (StringUtils.hasText(id)) ? id :
BeanDefinitionReaderUtils.generateBeanName(handlerAdapterDef, parserContext.getRegistry(), isInnerHandler);
BeanDefinition handlerDef = new RootBeanDefinition(DefaultMessageHandler.class);
handlerDef.getPropertyValues().addPropertyValue(OBJECT_PROPERTY, new RuntimeBeanReference(handlerRef));
handlerDef.getPropertyValues().addPropertyValue(METHOD_NAME_PROPERTY, handlerMethod);
String handlerBeanName = (StringUtils.hasText(id)) ? id :
BeanDefinitionReaderUtils.generateBeanName(handlerDef, parserContext.getRegistry(), isInnerHandler);
if (!isInnerHandler) {
parserContext.registerBeanComponent(new BeanComponentDefinition(handlerAdapterDef, adapterBeanName));
parserContext.registerBeanComponent(new BeanComponentDefinition(handlerDef, handlerBeanName));
}
return new BeanDefinitionHolder(handlerAdapterDef, adapterBeanName);
return new BeanDefinitionHolder(handlerDef, handlerBeanName);
}
}

View File

@@ -20,22 +20,17 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.Ordered;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.handler.annotation.Header;
import org.springframework.integration.handler.annotation.MethodArgumentMessageMapper;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.MessageHeaders;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.util.DefaultMethodInvoker;
import org.springframework.integration.util.MethodInvoker;
import org.springframework.integration.util.NameResolvingMethodInvoker;
@@ -54,9 +49,9 @@ import org.springframework.util.StringUtils;
*
* @author Mark Fisher
*/
public abstract class AbstractMessageHandler implements MessageHandler, InitializingBean {
public abstract class AbstractMessageHandler implements MessageHandler, Ordered, InitializingBean {
private static final Log logger = LogFactory.getLog(AbstractMessageHandler.class);
protected static final Log logger = LogFactory.getLog(AbstractMessageHandler.class);
private volatile boolean methodExpectsMessage;
@@ -66,11 +61,11 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
private volatile String methodName;
private volatile MessageMapper<Object, Object[]> methodArgumentMapper;
private volatile MethodInvoker invoker;
private volatile MethodParameterMetadata[] parameterMetadata;
private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private volatile int order = Ordered.LOWEST_PRECEDENCE;
private volatile boolean initialized;
@@ -99,10 +94,11 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
public void setMethod(Method method) {
Assert.notNull(method, "method must not be null");
if (method.getParameterTypes().length == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
throw new ConfigurationException("method must accept at least one parameter");
}
if (method.getParameterTypes()[0].equals(Message.class)) {
if (parameterTypes.length == 1 && Message.class.isAssignableFrom(parameterTypes[0])) {
this.methodExpectsMessage = true;
}
this.method = method;
@@ -117,6 +113,14 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
this.methodName = methodName;
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return order;
}
public void afterPropertiesSet() {
synchronized (this.initializationMonitor) {
if (this.initialized) {
@@ -145,42 +149,17 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
}
if (this.method != null) {
this.invoker = new DefaultMethodInvoker(this.object, this.method);
this.methodArgumentMapper = new MethodArgumentMessageMapper(this.method);
}
else {
// TODO: resolve the candidate method and/or create a dynamic resolver
this.invoker = new NameResolvingMethodInvoker(this.object, this.methodName);
}
this.configureParameterMetadata();
}
this.initialized = true;
}
}
private void configureParameterMetadata() {
if (this.method == null) {
return;
}
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();
String headerName = null;
for (int j = 0; j < paramAnnotations.length; j++) {
if (Header.class.isInstance(paramAnnotations[j])) {
Header headerAnnotation = (Header) paramAnnotations[j];
headerName = this.resolveParameterNameIfNecessary(headerAnnotation.value(), methodParam);
parameterMetadata[i] = new MethodParameterMetadata(Header.class, headerName, headerAnnotation.required());
}
}
if (headerName == null) {
parameterMetadata[i] = new MethodParameterMetadata(methodParam.getParameterType(), null, false);
}
}
}
public Message<?> handle(Message<?> requestMessage) {
if (requestMessage == null || requestMessage.getPayload() == null) {
if (logger.isDebugEnabled()) {
@@ -196,11 +175,25 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
if (result == null) {
return null;
}
if (result instanceof Message) {
return this.postProcessReplyMessage((Message<?>) result, requestMessage);
}
return this.createReplyMessage(result, requestMessage);
}
/**
* Subclasses must implement this method to generate the reply Message.
* Subclasses must implement this method to process a return value that
* is already a Message instance.
*
* @param replyMessage the Message returned from an adapter method
* @param requestMessage the original request Message
* @return the Message to be sent to the reply MessageTarget
*/
protected abstract Message<?> postProcessReplyMessage(Message<?> replyMessage, Message<?> requestMessage);
/**
* Subclasses must implement this method to generate the reply Message when
* the return value is not a Message instance.
*
* @param result the return value from an adapter method, or the Message payload if not acting as an adapter
* @param requestMessage the original request Message
@@ -210,9 +203,6 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
private Object invokeHandlerMethod(Message<?> message) {
if (this.invoker == null) {
throw new IllegalStateException("cannot invoke method, invoker is null");
}
Object args[] = null;
Object mappingResult = this.methodExpectsMessage ? message
: this.mapMessageToMethodArguments(message);
@@ -253,86 +243,11 @@ public abstract class AbstractMessageHandler implements MessageHandler, Initiali
}
}
private Object[] mapMessageToMethodArguments(Message<?> message) {
if (message == null) {
return null;
private Object[] mapMessageToMethodArguments(Message message) {
if (this.methodArgumentMapper != null) {
return this.methodArgumentMapper.mapMessage(message);
}
if (message.getPayload() == null) {
throw new IllegalArgumentException("Message payload must not be null.");
}
if (ObjectUtils.isEmpty(this.parameterMetadata)) {
return new Object[] { message.getPayload() };
}
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) {
throw new MessageHandlingException(message,
"required header '" + metadata.key + "' not available");
}
args[i] = value;
}
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();
}
}
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;
}
private String resolveParameterNameIfNecessary(String paramName, MethodParameter methodParam) {
if (!StringUtils.hasText(paramName)) {
paramName = methodParam.getParameterName();
if (paramName == null) {
throw new IllegalStateException("No parameter name specified and not available in class file.");
}
}
return paramName;
}
private static class MethodParameterMetadata {
private final Class<?> type;
private final String key;
private final boolean required;
MethodParameterMetadata(Class<?> type, String key, boolean required) {
this.type = type;
this.key = key;
this.required = required;
}
return new Object[] { message.getPayload() };
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.integration.handler;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHeaders;
/**
* The default MessageHandler implementation. Creates a Message for the reply payload.
@@ -30,9 +31,17 @@ public class DefaultMessageHandler extends AbstractMessageHandler {
@Override
protected Message<?> createReplyMessage(Object result, Message<?> requestMessage) {
return MessageBuilder.fromPayload(result)
.copyHeaders(requestMessage.getHeaders())
.setCorrelationId(requestMessage.getHeaders().getId())
return this.prepareReplyMessage(MessageBuilder.fromPayload(result), requestMessage.getHeaders());
}
@Override
protected Message<?> postProcessReplyMessage(Message<?> replyMessage, Message<?> requestMessage) {
return this.prepareReplyMessage(MessageBuilder.fromMessage(replyMessage), requestMessage.getHeaders());
}
private Message<?> prepareReplyMessage(MessageBuilder<?> builder, MessageHeaders requestHeaders) {
return builder.copyHeadersIfAbsent(requestHeaders)
.setHeaderIfAbsent(MessageHeaders.CORRELATION_ID, requestHeaders.getId())
.build();
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright 2002-2008 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.handler;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageCreator;
/**
* An implementation of {@link MessageHandler} that invokes the specified method and target object.
* It will use the provided implementation of the {@link MessageCreator} strategy interface to convert
* the method invocation's return value to a reply Message.
*
* @author Mark Fisher
*/
public class DefaultMessageHandlerAdapter extends AbstractMessageHandlerAdapter {
protected Message<?> handleReturnValue(Object returnValue, Message<?> originalMessage) {
return this.createReplyMessage(returnValue, originalMessage);
}
}

View File

@@ -34,11 +34,21 @@ public class MethodInvokingTarget extends AbstractMessageHandler implements Mess
@Override
protected Message<?> createReplyMessage(Object result, Message<?> requestMessage) {
if (result != null) {
throw new MessagingException(requestMessage, "The target method returned a non-null Object. " +
"MethodInvokingTarget should only be used for methods that return no value (preferably void).");
}
this.failIfNotNull(result, requestMessage);
return null;
}
@Override
protected Message<?> postProcessReplyMessage(Message<?> replyMessage, Message<?> requestMessage) {
this.failIfNotNull(replyMessage, requestMessage);
return null;
}
private void failIfNotNull(Object result, Message<?> requestMessage) {
if (result != null) {
throw new MessagingException(requestMessage, "the MethodInvokingTarget method must have a void or null return, "
+ "but '" + this + "' received a non-null value: [" + result + "]");
}
}
}

View File

@@ -29,80 +29,50 @@ import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.MessageHeaders;
import org.springframework.integration.message.MessageMapper;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* A {@link MessageMapper} implementation for annotated handler methods.
* Method parameters are matched against the Message payload as well as its
* headers. 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). If neither annotation is present, then
* the parameter will typically match the Message payload. However, if a Map or
* Properties object is expected, and the paylaod is not itself assignable 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.
* Prepares arguments for handler methods. The method parameters are matched
* against the Message payload as well as its headers. 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).
* If the {@link Header @Header} annotation is not present, then the parameter
* will typically match the Message payload. However, if a Map or Properties
* object is expected, and the paylaod is not itself assignable 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.
*
* @author Mark Fisher
*/
public class AnnotationMethodMessageMapper implements MessageMapper {
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
public class MethodArgumentMessageMapper<T extends Object> implements MessageMapper<T, Object[]> {
private final Method method;
private MethodParameterMetadata[] parameterMetadata;
private volatile MethodParameterMetadata[] parameterMetadata;
private volatile boolean initialized;
private final Object initializationMonitor = new Object();
private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
public AnnotationMethodMessageMapper(Method method) {
public MethodArgumentMessageMapper(Method method) {
Assert.notNull(method, "method must not be null");
this.method = method;
this.initializeParameterMetadata();
}
public void initialize() {
synchronized (this.initializationMonitor) {
if (this.initialized) {
return;
}
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();
String headerName = null;
for (int j = 0; j < paramAnnotations.length; j++) {
if (Header.class.isInstance(paramAnnotations[j])) {
Header headerAnnotation = (Header) paramAnnotations[j];
headerName = this.resolveParameterNameIfNecessary(headerAnnotation.value(), methodParam);
parameterMetadata[i] = new MethodParameterMetadata(Header.class, headerName, headerAnnotation.required());
}
}
if (headerName == null) {
parameterMetadata[i] = new MethodParameterMetadata(methodParam.getParameterType(), null, false);
}
}
this.initialized = true;
}
}
public Object[] mapMessage(Message message) {
public Object[] mapMessage(Message<T> message) {
if (message == null) {
return null;
}
if (message.getPayload() == null) {
throw new IllegalArgumentException("Message payload must not be null.");
}
if (!this.initialized) {
this.initialize();
if (ObjectUtils.isEmpty(this.parameterMetadata)) {
return new Object[] { message.getPayload() };
}
Object[] args = new Object[this.parameterMetadata.length];
for (int i = 0; i < this.parameterMetadata.length; i++) {
@@ -135,6 +105,28 @@ public class AnnotationMethodMessageMapper implements MessageMapper {
return args;
}
private void initializeParameterMetadata() {
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();
String headerName = null;
for (int j = 0; j < paramAnnotations.length; j++) {
if (Header.class.isInstance(paramAnnotations[j])) {
Header headerAnnotation = (Header) paramAnnotations[j];
headerName = this.resolveParameterNameIfNecessary(headerAnnotation.value(), methodParam);
parameterMetadata[i] = new MethodParameterMetadata(Header.class, headerName, headerAnnotation.required());
}
}
if (headerName == null) {
parameterMetadata[i] = new MethodParameterMetadata(methodParam.getParameterType(), null, false);
}
}
}
private Properties getStringTypedHeaders(Message<?> message) {
Properties properties = new Properties();
MessageHeaders headers = message.getHeaders();

View File

@@ -21,8 +21,8 @@ import java.util.Map;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
/**
* Base class for handler creators that generate a {@link MessageHandler}
@@ -34,10 +34,10 @@ public abstract class AbstractMessageHandlerCreator implements MessageHandlerCre
public final MessageHandler createHandler(Object object, Method method, Map<String, ?> attributes) {
MessageHandler handler = this.doCreateHandler(object, method, attributes);
if (attributes != null && handler instanceof AbstractMethodInvokingAdapter) {
if (attributes != null && handler instanceof AbstractMessageHandler) {
Object order = attributes.get("order");
if (order != null && order instanceof Integer) {
((AbstractMethodInvokingAdapter) handler).setOrder(((Integer) order).intValue());
((AbstractMessageHandler) handler).setOrder(((Integer) order).intValue());
}
}
if (handler instanceof InitializingBean) {

View File

@@ -19,32 +19,23 @@ package org.springframework.integration.handler.config;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.core.annotation.Order;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
import org.springframework.integration.handler.DefaultMessageHandler;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
/**
* Default implementation of the handler creator strategy that creates a
* {@link DefaultMessageHandlerAdapter} for the provided object and method.
* This version does not even consider the attributes. It does however respect
* an {@link Order} annotation if present.
* {@link DefaultMessageHandler} for the provided object and method.
*
* @author Mark Fisher
*/
public class DefaultMessageHandlerCreator extends AbstractMessageHandlerCreator {
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
Class<?>[] types = method.getParameterTypes();
if (types.length != 1) {
throw new ConfigurationException("exactly one method parameter is required");
}
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(object);
adapter.setMethodName(method.getName());
adapter.setMethodExpectsMessage(Message.class.isAssignableFrom(types[0]));
return adapter;
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(object);
handler.setMethod(method);
handler.afterPropertiesSet();
return handler;
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.message.CompositeMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.MessageTarget;
/**
@@ -101,4 +102,10 @@ public class RouterMessageHandler extends AbstractMessageHandler {
return new CompositeMessage(replies);
}
@Override
protected Message<?> postProcessReplyMessage(Message<?> replyMessage, Message<?> requestMessage) {
throw new MessageHandlingException(requestMessage,
"router method must return type 'MessageChannel' or 'String', but a Message was returned: " + replyMessage);
}
}

View File

@@ -108,6 +108,23 @@ public class SplitterMessageHandler extends AbstractMessageHandler {
return new CompositeMessage(results);
}
@Override
protected Message<?> postProcessReplyMessage(Message<?> replyMessage, Message<?> requestMessage) {
Object requestId = requestMessage.getHeaders().getId();
if (replyMessage instanceof CompositeMessage) {
List<Message<?>> sequentialMessages = new ArrayList<Message<?>>();
List<Message<?>> replyList = ((CompositeMessage) replyMessage).getPayload();
int sequenceSize = replyList.size();
int sequenceNumber = 0;
for (Message<?> message : replyList) {
sequentialMessages.add(this.setSplitMessageHeaders(
MessageBuilder.fromMessage(message), requestId, ++sequenceNumber, sequenceSize));
}
return new CompositeMessage(sequentialMessages);
}
return this.setSplitMessageHeaders(MessageBuilder.fromMessage(replyMessage), requestId, 1, 1);
}
private Message<?> createSplitMessage(Object item, MessageHeaders requestHeaders, int sequenceNumber, int sequenceSize) {
if (item instanceof Message<?>) {
return this.setSplitMessageHeaders(MessageBuilder.fromMessage((Message<?>) item),

View File

@@ -1,113 +0,0 @@
/*
* Copyright 2002-2008 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.transformer;
import java.util.Map;
import java.util.Properties;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.handler.annotation.AnnotationMethodMessageMapper;
import org.springframework.integration.message.DefaultMessageMapper;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.MessagingException;
import org.springframework.integration.util.AbstractMethodInvokingAdapter;
/**
* @author Mark Fisher
*/
@SuppressWarnings("unchecked")
public class AnnotationMethodTransformerAdapter extends AbstractMethodInvokingAdapter implements MessageHandler {
private volatile MessageMapper mapper;
private volatile boolean methodExpectsMessage;
public void setMethodExpectsMessage(boolean methodExpectsMessage) {
this.methodExpectsMessage = methodExpectsMessage;
}
protected void initialize() {
this.mapper = (this.getMethod() != null)
? new AnnotationMethodMessageMapper(this.getMethod())
: new DefaultMessageMapper();
}
public Message<?> handle(Message<?> message) {
if (!this.isInitialized()) {
this.afterPropertiesSet();
}
if (message.getPayload() == null) {
return message;
}
Object param = (this.methodExpectsMessage) ? message : this.mapper.mapMessage(message);
try {
Object args[] = null;
if (param != null && param.getClass().isArray()
&& (Object.class.isAssignableFrom(param.getClass().getComponentType()))) {
args = (Object[]) param;
}
else {
args = new Object[] { param };
}
return this.invokeMethodAndReturnMessage(message, args);
}
catch (Exception e) {
throw new MessagingException(message, "failed to transform message payload", e);
}
}
private Message<?> invokeMethodAndReturnMessage(Message<?> message, Object[] args) throws Exception {
Object result = null;
try {
result = this.invokeMethod(args);
}
catch (NoSuchMethodException e) {
result = this.invokeMethod(message);
this.methodExpectsMessage = true;
}
if (result == null) {
if (logger.isDebugEnabled()) {
logger.debug("handler invocation returned a null result");
}
return null;
}
if (result instanceof Properties && !(message.getPayload() instanceof Properties)) {
Properties propertiesToSet = (Properties) result;
MessageBuilder builder = MessageBuilder.fromMessage(message);
for (Object keyObject : propertiesToSet.keySet()) {
String key = (String) keyObject;
builder.setHeader(key, propertiesToSet.getProperty(key));
}
return builder.build();
}
else if (result instanceof Map && !(message.getPayload() instanceof Map)) {
Map<String, ?> attributesToSet = (Map) result;
MessageBuilder builder = MessageBuilder.fromMessage(message);
for (String key : attributesToSet.keySet()) {
builder.setHeader(key, attributesToSet.get(key));
}
return builder.build();
}
else {
return MessageBuilder.fromPayload(result).copyHeaders(message.getHeaders()).build();
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2008 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.transformer;
import java.util.Map;
import java.util.Properties;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandlingException;
/**
* @author Mark Fisher
*/
public class TransformerMessageHandler extends AbstractMessageHandler {
@Override
protected Message<?> createReplyMessage(Object result, Message<?> requestMessage) {
if (result instanceof Properties && !(requestMessage.getPayload() instanceof Properties)) {
Properties propertiesToSet = (Properties) result;
MessageBuilder<?> builder = MessageBuilder.fromMessage(requestMessage);
for (Object keyObject : propertiesToSet.keySet()) {
String key = (String) keyObject;
builder.setHeader(key, propertiesToSet.getProperty(key));
}
return builder.build();
}
else if (result instanceof Map && !(requestMessage.getPayload() instanceof Map)) {
Map<?, ?> attributesToSet = (Map <?, ?>) result;
MessageBuilder<?> builder = MessageBuilder.fromMessage(requestMessage);
for (Object key : attributesToSet.keySet()) {
if (!(key instanceof String)) {
throw new MessageHandlingException(requestMessage,
"Map returned from a Transformer method must have String-typed keys");
}
builder.setHeader((String) key, attributesToSet.get(key));
}
return builder.build();
}
else {
return MessageBuilder.fromPayload(result).copyHeaders(requestMessage.getHeaders()).build();
}
}
@Override
protected Message<?> postProcessReplyMessage(Message<?> replyMessage, Message<?> requestMessage) {
return replyMessage;
}
}

View File

@@ -21,7 +21,7 @@ import java.util.Map;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.handler.config.AbstractMessageHandlerCreator;
import org.springframework.integration.transformer.AnnotationMethodTransformerAdapter;
import org.springframework.integration.transformer.TransformerMessageHandler;
/**
* @author Mark Fisher
@@ -29,11 +29,11 @@ import org.springframework.integration.transformer.AnnotationMethodTransformerAd
public class TransformerMessageHandlerCreator extends AbstractMessageHandlerCreator {
public MessageHandler doCreateHandler(Object object, Method method, Map<String, ?> attributes) {
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(object);
adapter.setMethodName(method.getName());
adapter.afterPropertiesSet();
return adapter;
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(object);
handler.setMethodName(method.getName());
handler.afterPropertiesSet();
return handler;
}
}

View File

@@ -38,7 +38,7 @@ public class DefaultMethodInvoker implements MethodInvoker {
private final Object object;
private final Method method;
private volatile Method method;
private volatile TypeConverter typeConverter;
@@ -85,7 +85,18 @@ public class DefaultMethodInvoker implements MethodInvoker {
if (this.logger.isDebugEnabled()) {
logger.debug("invoking method '" + this.method.getName() + "' with arguments " + ObjectUtils.nullSafeToString(convertedArgs));
}
return this.method.invoke(this.object, convertedArgs);
try {
return this.method.invoke(this.object, convertedArgs);
}
catch (IllegalArgumentException e) {
org.springframework.util.MethodInvoker helper = new org.springframework.util.MethodInvoker();
helper.setTargetObject(this.object);
helper.setTargetMethod(this.method.getName());
helper.setArguments(convertedArgs);
helper.prepare();
this.method = helper.getPreparedMethod();
return this.method.invoke(this.object, convertedArgs);
}
}
}

View File

@@ -39,22 +39,22 @@ public class CorrelationIdTests {
Object correlationId = "123-ABC";
Message<String> message = MessageBuilder.fromPayload("test")
.setCorrelationId(correlationId).build();
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(new TestBean());
adapter.setMethodName("upperCase");
adapter.afterPropertiesSet();
Message<?> reply = adapter.handle(message);
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestBean());
handler.setMethodName("upperCase");
handler.afterPropertiesSet();
Message<?> reply = handler.handle(message);
assertEquals(correlationId, reply.getHeaders().getCorrelationId());
}
@Test
public void testCorrelationIdCopiedFromMessageIdByDefault() {
Message<String> message = MessageBuilder.fromPayload("test").build();
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(new TestBean());
adapter.setMethodName("upperCase");
adapter.afterPropertiesSet();
Message<?> reply = adapter.handle(message);
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestBean());
handler.setMethodName("upperCase");
handler.afterPropertiesSet();
Message<?> reply = handler.handle(message);
assertEquals(message.getHeaders().getId(), reply.getHeaders().getCorrelationId());
}
@@ -62,11 +62,11 @@ public class CorrelationIdTests {
public void testCorrelationIdCopiedFromMessageCorrelationIdIfAvailable() {
Message<String> message = MessageBuilder.fromPayload("test")
.setCorrelationId("correlationId").build();
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(new TestBean());
adapter.setMethodName("upperCase");
adapter.afterPropertiesSet();
Message<?> reply = adapter.handle(message);
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestBean());
handler.setMethodName("upperCase");
handler.afterPropertiesSet();
Message<?> reply = handler.handle(message);
assertEquals(message.getHeaders().getCorrelationId(), reply.getHeaders().getCorrelationId());
assertTrue(message.getHeaders().getCorrelationId().equals(reply.getHeaders().getCorrelationId()));
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright 2002-2008 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.handler;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.StringMessage;
/**
* @author Mark Fisher
*/
public class DefaultMessageHandlerAdapterTests {
@Test
public void testPayloadAsMethodParameterAndObjectAsReturnValue() {
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(new TestHandler());
adapter.setMethodName("acceptPayloadAndReturnObject");
adapter.afterPropertiesSet();
Message<?> result = adapter.handle(new StringMessage("testing"));
assertEquals("testing-1", result.getPayload());
}
@Test
public void testPayloadAsMethodParameterAndMessageAsReturnValue() {
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(new TestHandler());
adapter.setMethodName("acceptPayloadAndReturnMessage");
adapter.afterPropertiesSet();
Message<?> result = adapter.handle(new StringMessage("testing"));
assertEquals("testing-2", result.getPayload());
}
@Test
public void testMessageAsMethodParameterAndObjectAsReturnValue() {
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setMethodExpectsMessage(true);
adapter.setObject(new TestHandler());
adapter.setMethodName("acceptMessageAndReturnObject");
adapter.afterPropertiesSet();
Message<?> result = adapter.handle(new StringMessage("testing"));
assertEquals("testing-3", result.getPayload());
}
@Test
public void testMessageAsMethodParameterAndMessageAsReturnValue() {
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setMethodExpectsMessage(true);
adapter.setObject(new TestHandler());
adapter.setMethodName("acceptMessageAndReturnMessage");
adapter.afterPropertiesSet();
Message<?> result = adapter.handle(new StringMessage("testing"));
assertEquals("testing-4", result.getPayload());
}
@Test
public void testMessageSubclassAsMethodParameterAndMessageAsReturnValue() {
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setMethodExpectsMessage(true);
adapter.setObject(new TestHandler());
adapter.setMethodName("acceptMessageSubclassAndReturnMessage");
adapter.afterPropertiesSet();
Message<?> result = adapter.handle(new StringMessage("testing"));
assertEquals("testing-5", result.getPayload());
}
@Test
public void testMessageSubclassAsMethodParameterAndMessageSubclassAsReturnValue() {
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setMethodExpectsMessage(true);
adapter.setObject(new TestHandler());
adapter.setMethodName("acceptMessageSubclassAndReturnMessageSubclass");
adapter.afterPropertiesSet();
Message<?> result = adapter.handle(new StringMessage("testing"));
assertEquals("testing-6", result.getPayload());
}
private static class TestHandler {
public String acceptPayloadAndReturnObject(String s) {
return s + "-1";
}
public Message<?> acceptPayloadAndReturnMessage(String s) {
return new StringMessage(s + "-2");
}
public String acceptMessageAndReturnObject(Message<?> m) {
return m.getPayload() + "-3";
}
public Message<?> acceptMessageAndReturnMessage(Message<?> m) {
return new StringMessage(m.getPayload() + "-4");
}
public Message<?> acceptMessageSubclassAndReturnMessage(StringMessage m) {
return new StringMessage(m.getPayload() + "-5");
}
public StringMessage acceptMessageSubclassAndReturnMessageSubclass(StringMessage m) {
return new StringMessage(m.getPayload() + "-6");
}
}
}

View File

@@ -0,0 +1,264 @@
/*
* Copyright 2002-2008 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.handler;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import org.junit.Test;
import org.springframework.integration.annotation.Handler;
import org.springframework.integration.handler.annotation.Header;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessagingException;
import org.springframework.integration.message.StringMessage;
/**
* @author Mark Fisher
*/
public class DefaultMessageHandlerTests {
@Test
public void payloadAsMethodParameterAndObjectAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptPayloadAndReturnObject");
handler.afterPropertiesSet();
Message<?> result = handler.handle(new StringMessage("testing"));
assertEquals("testing-1", result.getPayload());
}
@Test
public void payloadAsMethodParameterAndMessageAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptPayloadAndReturnMessage");
handler.afterPropertiesSet();
Message<?> result = handler.handle(new StringMessage("testing"));
assertEquals("testing-2", result.getPayload());
}
@Test
public void messageAsMethodParameterAndObjectAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptMessageAndReturnObject");
handler.afterPropertiesSet();
Message<?> result = handler.handle(new StringMessage("testing"));
assertEquals("testing-3", result.getPayload());
}
@Test
public void messageAsMethodParameterAndMessageAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptMessageAndReturnMessage");
handler.afterPropertiesSet();
Message<?> result = handler.handle(new StringMessage("testing"));
assertEquals("testing-4", result.getPayload());
}
@Test
public void messageSubclassAsMethodParameterAndMessageAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptMessageSubclassAndReturnMessage");
handler.afterPropertiesSet();
Message<?> result = handler.handle(new StringMessage("testing"));
assertEquals("testing-5", result.getPayload());
}
@Test
public void messageSubclassAsMethodParameterAndMessageSubclassAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptMessageSubclassAndReturnMessageSubclass");
handler.afterPropertiesSet();
Message<?> result = handler.handle(new StringMessage("testing"));
assertEquals("testing-6", result.getPayload());
}
@Test
public void payloadAndHeaderAnnotationMethodParametersAndObjectAsReturnValue() {
DefaultMessageHandler handler = new DefaultMessageHandler();
handler.setObject(new TestHandler());
handler.setMethodName("acceptPayloadAndHeaderAndReturnObject");
handler.afterPropertiesSet();
Message<?> request = MessageBuilder.fromPayload("testing")
.setHeader("number", new Integer(123)).build();
Message<?> result = handler.handle(request);
assertEquals("testing-123", result.getPayload());
}
@Test
public void messageOnlyWithAnnotatedMethod() throws Exception {
AnnotatedTestHandler handler = new AnnotatedTestHandler();
Method method = handler.getClass().getMethod("messageOnly", Message.class);
DefaultMessageHandler adapter = new DefaultMessageHandler();
adapter.setObject(handler);
adapter.setMethod(method);
Message<?> result = adapter.handle(new StringMessage("foo"));
assertEquals("foo", result.getPayload());
}
@Test
public void payloadWithAnnotatedMethod() throws Exception {
AnnotatedTestHandler handler = new AnnotatedTestHandler();
Method method = handler.getClass().getMethod("integerMethod", Integer.class);
DefaultMessageHandler adapter = new DefaultMessageHandler();
adapter.setObject(handler);
adapter.setMethod(method);
Message<?> result = adapter.handle(new GenericMessage<Integer>(new Integer(123)));
assertEquals(new Integer(123), result.getPayload());
}
@Test
public void convertedPayloadWithAnnotatedMethod() throws Exception {
AnnotatedTestHandler handler = new AnnotatedTestHandler();
Method method = handler.getClass().getMethod("integerMethod", Integer.class);
DefaultMessageHandler adapter = new DefaultMessageHandler();
adapter.setObject(handler);
adapter.setMethod(method);
Message<?> result = adapter.handle(new StringMessage("456"));
assertEquals(new Integer(456), result.getPayload());
}
@Test(expected = MessagingException.class)
public void conversionFailureWithAnnotatedMethod() throws Exception {
AnnotatedTestHandler handler = new AnnotatedTestHandler();
Method method = handler.getClass().getMethod("integerMethod", Integer.class);
DefaultMessageHandler adapter = new DefaultMessageHandler();
adapter.setObject(handler);
adapter.setMethod(method);
Message<?> result = adapter.handle(new StringMessage("foo"));
assertEquals(new Integer(123), result.getPayload());
}
@Test
public void messageAndHeaderWithAnnotatedMethod() throws Exception {
AnnotatedTestHandler handler = new AnnotatedTestHandler();
Method method = handler.getClass().getMethod("messageAndHeader", Message.class, Integer.class);
DefaultMessageHandler adapter = new DefaultMessageHandler();
adapter.setObject(handler);
adapter.setMethod(method);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("number", 42).build();
Message<?> result = adapter.handle(message);
assertEquals("foo-42", result.getPayload());
}
@Test
public void multipleHeadersWithAnnotatedMethod() throws Exception {
AnnotatedTestHandler handler = new AnnotatedTestHandler();
Method method = handler.getClass().getMethod("twoHeaders", String.class, Integer.class);
DefaultMessageHandler adapter = new DefaultMessageHandler();
adapter.setObject(handler);
adapter.setMethod(method);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("prop", "bar")
.setHeader("number", 42).build();
Message<?> result = adapter.handle(message);
assertEquals("bar-42", result.getPayload());
}
private static class TestHandler {
public String acceptPayloadAndReturnObject(String s) {
return s + "-1";
}
public Message<?> acceptPayloadAndReturnMessage(String s) {
return new StringMessage(s + "-2");
}
public String acceptMessageAndReturnObject(Message<?> m) {
return m.getPayload() + "-3";
}
public Message<?> acceptMessageAndReturnMessage(Message<?> m) {
return new StringMessage(m.getPayload() + "-4");
}
public Message<?> acceptMessageSubclassAndReturnMessage(StringMessage m) {
return new StringMessage(m.getPayload() + "-5");
}
public StringMessage acceptMessageSubclassAndReturnMessageSubclass(StringMessage m) {
return new StringMessage(m.getPayload() + "-6");
}
public String acceptPayloadAndHeaderAndReturnObject(String s, @Header("number") Integer n) {
return s + "-" + n;
}
}
private static class AnnotatedTestHandler {
@Handler
public String messageOnly(Message<?> message) {
return (String) message.getPayload();
}
@Handler
public String messageAndHeader(Message<?> message, @Header("number") Integer num) {
return (String) message.getPayload() + "-" + num.toString();
}
@Handler
public String twoHeaders(@Header String prop, @Header("number") Integer num) {
return prop + "-" + num.toString();
}
@Handler
public Integer optionalHeader(@Header(required=false) Integer num) {
return num;
}
@Handler
public Integer requiredHeader(@Header(value="num", required=true) Integer num) {
return num;
}
@Handler
public String optionalAndRequiredHeader(@Header(required=false) String prop, @Header(value="num", required=true) Integer num) {
return prop + num;
}
@Handler
public Properties propertiesMethod(Properties properties) {
return properties;
}
@Handler
@SuppressWarnings("unchecked")
public Map mapMethod(Map map) {
return map;
}
@Handler
public Integer integerMethod(Integer i) {
return i;
}
}
}

View File

@@ -27,23 +27,20 @@ import java.util.Properties;
import org.junit.Test;
import org.springframework.integration.annotation.Handler;
import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.MessagingException;
import org.springframework.integration.message.StringMessage;
/**
* @author Mark Fisher
*/
public class AnnotationMethodMessageMapperTests {
public class MethodArgumentMessageMapperTests {
@Test
public void testOptionalHeader() throws Exception {
Method method = TestHandler.class.getMethod("optionalHeader", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Object[] args = (Object[]) mapper.mapMessage(new StringMessage("foo"));
assertEquals(1, args.length);
assertNull(args[0]);
@@ -52,14 +49,14 @@ public class AnnotationMethodMessageMapperTests {
@Test(expected=MessageHandlingException.class)
public void testRequiredHeaderNotProvided() throws Exception {
Method method = TestHandler.class.getMethod("requiredHeader", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
mapper.mapMessage(new StringMessage("foo"));
}
@Test
public void testRequiredHeaderProvided() throws Exception {
Method method = TestHandler.class.getMethod("requiredHeader", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("num", new Integer(123)).build();
Object[] args = (Object[]) mapper.mapMessage(message);
@@ -70,7 +67,7 @@ public class AnnotationMethodMessageMapperTests {
@Test(expected=MessageHandlingException.class)
public void testOptionalAndRequiredHeaderWithOnlyOptionalHeaderProvided() throws Exception {
Method method = TestHandler.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("prop", "bar").build();
mapper.mapMessage(message);
@@ -79,7 +76,7 @@ public class AnnotationMethodMessageMapperTests {
@Test
public void testOptionalAndRequiredHeaderWithOnlyRequiredHeaderProvided() throws Exception {
Method method = TestHandler.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("num", new Integer(123)).build();
Object[] args = (Object[]) mapper.mapMessage(message);
@@ -91,7 +88,7 @@ public class AnnotationMethodMessageMapperTests {
@Test
public void testOptionalAndRequiredHeaderWithBothHeadersProvided() throws Exception {
Method method = TestHandler.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("num", new Integer(123))
.setHeader("prop", "bar")
@@ -105,7 +102,7 @@ public class AnnotationMethodMessageMapperTests {
@Test
public void testPropertiesMethodWithNonPropertiesPayload() throws Exception {
Method method = TestHandler.class.getMethod("propertiesMethod", Properties.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Message<String> message = MessageBuilder.fromPayload("test")
.setHeader("prop1", "foo").setHeader("prop2", "bar").build();
Object[] args = (Object[]) mapper.mapMessage(message);
@@ -118,7 +115,7 @@ public class AnnotationMethodMessageMapperTests {
@Test
public void testPropertiesMethodWithPropertiesPayload() throws Exception {
Method method = TestHandler.class.getMethod("propertiesMethod", Properties.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<Properties> mapper = new MethodArgumentMessageMapper<Properties>(method);
Properties payload = new Properties();
payload.setProperty("prop1", "foo");
payload.setProperty("prop2", "bar");
@@ -135,7 +132,7 @@ public class AnnotationMethodMessageMapperTests {
@SuppressWarnings("unchecked")
public void testMapMethodWithNonMapPayload() throws Exception {
Method method = TestHandler.class.getMethod("mapMethod", Map.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<String> mapper = new MethodArgumentMessageMapper<String>(method);
Message<String> message = MessageBuilder.fromPayload("test")
.setHeader("attrib1", new Integer(123))
.setHeader("attrib2", new Integer(456)).build();
@@ -149,7 +146,7 @@ public class AnnotationMethodMessageMapperTests {
@SuppressWarnings("unchecked")
public void testMapMethodWithMapPayload() throws Exception {
Method method = TestHandler.class.getMethod("mapMethod", Map.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
MethodArgumentMessageMapper<Map<String,Integer>> mapper = new MethodArgumentMessageMapper<Map<String,Integer>>(method);
Map<String, Integer> payload = new HashMap<String, Integer>();
payload.put("attrib1", new Integer(123));
payload.put("attrib2", new Integer(456));
@@ -163,89 +160,6 @@ public class AnnotationMethodMessageMapperTests {
assertEquals(new Integer(456), result.get("attrib2"));
}
@Test
public void testMessageOnlyWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
Method method = handler.getClass().getMethod("messageOnly", Message.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
adapter.setMethod(method);
adapter.setMessageMapper(mapper);
Message<?> result = adapter.handle(new StringMessage("foo"));
assertEquals("foo", result.getPayload());
}
@Test
public void testPayloadWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
Method method = handler.getClass().getMethod("integerMethod", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
adapter.setMethod(method);
adapter.setMessageMapper(mapper);
Message<?> result = adapter.handle(new GenericMessage<Integer>(new Integer(123)));
assertEquals(new Integer(123), result.getPayload());
}
@Test
public void testConvertedPayloadWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
Method method = handler.getClass().getMethod("integerMethod", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
adapter.setMethod(method);
adapter.setMessageMapper(mapper);
Message<?> result = adapter.handle(new StringMessage("456"));
assertEquals(new Integer(456), result.getPayload());
}
@Test(expected=MessagingException.class)
public void testConversionFailureWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
Method method = handler.getClass().getMethod("integerMethod", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
adapter.setMethod(method);
adapter.setMessageMapper(mapper);
Message<?> result = adapter.handle(new StringMessage("foo"));
assertEquals(new Integer(123), result.getPayload());
}
@Test
public void testMessageAndHeaderWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
Method method = handler.getClass().getMethod("messageAndHeader", Message.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
adapter.setMethod(method);
adapter.setMessageMapper(mapper);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("number", 42).build();
Message<?> result = adapter.handle(message);
assertEquals("foo-42", result.getPayload());
}
@Test
public void testMultipleHeadersWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
Method method = handler.getClass().getMethod("twoHeaders", String.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
adapter.setMethod(method);
adapter.setMessageMapper(mapper);
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("prop", "bar")
.setHeader("number", 42).build();
Message<?> result = adapter.handle(message);
assertEquals("bar-42", result.getPayload());
}
private static class TestHandler {
@@ -294,7 +208,7 @@ public class AnnotationMethodMessageMapperTests {
public Integer integerMethod(Integer i) {
return i;
}
}
}

View File

@@ -36,84 +36,95 @@ import org.springframework.integration.message.StringMessage;
/**
* @author Mark Fisher
*/
public class AnnotationMethodTransformerAdapterTests {
public class TransformerMessageHandlerTests {
@Test
public void testSimplePayload() throws Exception {
public void simplePayload() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("exclaim", String.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("exclaim", String.class));
Message<?> message = new StringMessage("foo");
Message<?> result = adapter.handle(message);
Message<?> result = handler.handle(message);
assertEquals("FOO!", result.getPayload());
}
@Test
public void testTypeConversion() throws Exception {
public void typeConversion() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("exclaim", String.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("exclaim", String.class));
Message<?> message = new GenericMessage<Integer>(123);
Message<?> result = adapter.handle(message);
Message<?> result = handler.handle(message);
assertEquals("123!", result.getPayload());
}
@Test(expected=MessagingException.class)
public void testTypeConversionFailure() throws Exception {
@Test(expected = MessagingException.class)
public void typeConversionFailure() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("exclaim", String.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("exclaim", String.class));
Message<?> message = new GenericMessage<Date>(new Date());
adapter.handle(message);
handler.handle(message);
}
@Test
public void testHeaderAnnotation() throws Exception {
public void headerAnnotation() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("headerTest", String.class, Integer.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("headerTest", String.class, Integer.class));
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("number", 123).build();
Message<?> result = adapter.handle(message);
Message<?> result = handler.handle(message);
assertEquals("foo123", result.getPayload());
}
@Test(expected=MessageHandlingException.class)
public void testHeaderValueNotProvided() throws Exception {
@Test(expected = MessageHandlingException.class)
public void headerValueNotProvided() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("headerTest", String.class, Integer.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("headerTest", String.class, Integer.class));
Message<String> message = MessageBuilder.fromPayload("foo")
.setHeader("wrong", 123).build();
adapter.handle(message);
handler.handle(message);
}
@Test
public void testOptionalHeaderAnnotation() throws Exception {
public void optionalHeaderAnnotation() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("optionalHeaderTest", String.class, Integer.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("optionalHeaderTest", String.class, Integer.class));
Message<String> message = MessageBuilder.fromPayload("foo").setHeader("number", 99).build();
Message<?> result = handler.handle(message);
assertEquals("foo99", result.getPayload());
}
@Test
public void optionalHeaderValueNotProvided() throws Exception {
TestBean testBean = new TestBean();
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("optionalHeaderTest", String.class, Integer.class));
Message<String> message = MessageBuilder.fromPayload("foo").build();
Message<?> result = adapter.handle(message);
Message<?> result = handler.handle(message);
assertEquals("foonull", result.getPayload());
}
@Test
public void testHeaderEnricher() throws Exception {
public void headerEnricher() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("propertyEnricherTest", String.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("propertyEnricherTest", String.class));
Message<String> message = MessageBuilder.fromPayload("test")
.setHeader("prop1", "bad")
.setHeader("prop3", "baz").build();
Message<?> result = adapter.handle(message);
Message<?> result = handler.handle(message);
assertEquals("test", result.getPayload());
assertEquals("foo", result.getHeaders().get("prop1"));
assertEquals("bar", result.getHeaders().get("prop2"));
@@ -122,16 +133,16 @@ public class AnnotationMethodTransformerAdapterTests {
@Test
@SuppressWarnings("unchecked")
public void testPropertiesPayload() throws Exception {
public void propertiesPayload() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
adapter.setMethod(testBean.getClass().getMethod("propertyPayloadTest", Properties.class));
TransformerMessageHandler handler = new TransformerMessageHandler();
handler.setObject(testBean);
handler.setMethod(testBean.getClass().getMethod("propertyPayloadTest", Properties.class));
Properties props = new Properties();
props.setProperty("prop1", "bad");
props.setProperty("prop3", "baz");
Message<Properties> message = new GenericMessage<Properties>(props);
Message<Properties> result = (Message<Properties>) adapter.handle(message);
Message<Properties> result = (Message<Properties>) handler.handle(message);
assertEquals(Properties.class, result.getPayload().getClass());
Properties payload = result.getPayload();
assertEquals("foo", payload.getProperty("prop1"));