From 4a47d37e128ddb9a4f7aa58f4c95f6a97018bd1e Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Mon, 30 Nov 2009 22:45:46 +0000 Subject: [PATCH] INT-894, INT-895 Gateway proxy interface method parameters may now be annotated with @Payload. --- .../handler/ArgumentArrayMessageMapper.java | 155 +++++++++--------- 1 file changed, 80 insertions(+), 75 deletions(-) diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java index f8e72be214..b9f76da29f 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java @@ -39,6 +39,7 @@ import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.expression.spel.support.StandardTypeConverter; import org.springframework.integration.annotation.Header; import org.springframework.integration.annotation.Headers; import org.springframework.integration.annotation.Payload; @@ -118,13 +119,14 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper() { - public String convert(Number source) {return source.toString();} + public String convert(Number source) { return source.toString(); } }); registry.addConverter(new Converter() { - public String convert(Date source) {return source.toString();} + public String convert(Date source) { return source.toString(); } }); } + private final ExpressionParser expressionParser = new SpelExpressionParser(); private final Method method; @@ -133,21 +135,32 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper message) { - Assert.notNull(message, "Can not map Message with 'null' value"); + Assert.notNull(message, "cannot map a null Message"); this.validateMessageMapppings(message); - Map messageArgumentsMap = this.mapMessageToArguments(parameterList, message); - return messageArgumentsMap.values().toArray(); + return this.mapMessageToArguments(message); } - private Map mapMessageToArguments(List parameterList, Message message) { - Map messageArgumentsMap = new java.util.LinkedHashMap(); - for (MethodParameter methodParameter : parameterList) { + public Message toMessage(Object[] arguments) { + Assert.notNull(arguments, "cannot map null arguments to Message"); + if (arguments.length != this.parameterList.size()) { + String prefix = (arguments.length < this.parameterList.size()) ? "Not enough" : "Too many"; + throw new IllegalArgumentException(prefix + " parameters provided for method [" + method + + "], expected " + this.parameterList.size() + " but received " + arguments.length + "."); + } + Map messageArgumentsMap = this.mapArgumentsToMessage(arguments, null); + return this.buildMessageFromArgumentMap(messageArgumentsMap); + } + + private Object[] mapMessageToArguments(Message message) { + final Map messageArgumentsMap = new LinkedHashMap(); + for (MethodParameter methodParameter : this.parameterList) { String parameterName = methodParameter.getParameterName(); String[] expressions = null; Annotation mappingAnnotation = null; @@ -170,6 +183,10 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper toMessage(Object[] arguments) { - Assert.notNull(arguments, "cannot map null arguments to Message"); - if (arguments.length > this.parameterList.size()) { - throw new IllegalArgumentException("Too many parameters provided for: " + method); - } - else if (arguments.length < this.parameterList.size()) { - throw new IllegalArgumentException("Not enough parameters provided for: " + method); - } - else { - Map messageArgumentsMap = this.mapArgumentsToMessage(arguments, null); - return this.buildMessageFromArgumentMap(messageArgumentsMap); + messageArgumentsMap.put(methodParameter.getParameterIndex() + ":" + parameterName, value); } + return messageArgumentsMap.values().toArray(); } private Annotation findMappingAnnotation(Annotation[] annotations) { @@ -216,7 +215,7 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper type = annotation.annotationType(); if (type.equals(Payload.class) || type.equals(Header.class) || type.equals(Headers.class)) { if (match != null) { - throw new IllegalArgumentException("at most one parameter annotation can be provided for message mapping, " + + throw new IllegalArgumentException("At most one parameter annotation can be provided for message mapping, " + "but found two: [" + match.annotationType().getName() + "] and [" + annotation.annotationType().getName() + "]"); } match = annotation; @@ -227,43 +226,44 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper mapArgumentsToMessage(Object[] arguments, Message message) { - boolean payloadExist = false; + boolean mappedMessageOrPayload = false; Map messageArgumentsMap = new LinkedHashMap(); for (int i = 0; i < this.parameterList.size(); i++) { Object argumentValue = arguments[i]; MethodParameter methodParam = (MethodParameter) this.parameterList.get(i); - Annotation annotation = methodParam.getParameterAnnotations().length == 0 - ? null : (methodParam.getParameterAnnotations()[0]); - - if (annotation == null && !payloadExist) { + Annotation annotation = this.findMappingAnnotation(methodParam.getParameterAnnotations()); + if (annotation != null) { + if (annotation.annotationType().equals(Payload.class)) { + messageArgumentsMap.put("payload", argumentValue); + mappedMessageOrPayload = true; + } + else if (annotation.annotationType().equals(Header.class)) { + Object[] header = this.mapHeaderThruAnnotation(annotation, message, methodParam, argumentValue); + messageArgumentsMap.put((String) header[0], header[1]); + } + else if (annotation.annotationType().equals(Headers.class)) { + if (argumentValue != null) { + messageArgumentsMap.putAll(((Map) argumentValue)); + for (Object key : ((Map) argumentValue).keySet()) { + Assert.isInstanceOf(String.class, key, "Invalid header name [" + key + + "], name type must be String."); + Object value = ((Map) argumentValue).get(key); + messageArgumentsMap.put((String) key, value); + } + } + } + } + else if (!mappedMessageOrPayload) { if (argumentValue instanceof Message) { messageArgumentsMap.put("message", argumentValue); } else { messageArgumentsMap.put("payload", argumentValue); } - payloadExist = true; - } - else if (annotation.annotationType().equals(Headers.class)) { - if (argumentValue != null) { - messageArgumentsMap.putAll(((Map)argumentValue)); - for (Object key : ((Map)argumentValue).keySet()) { - Assert.isInstanceOf(String.class, key, "Header names must be of type String: " + key); - Object value = ((Map)argumentValue).get(key); - messageArgumentsMap.put((String) key, value); - } - } - } - else if (annotation.annotationType().equals(Header.class)) { - Object[] header = this.mapHeaderThruAnnotation(annotation, message, methodParam, argumentValue); - messageArgumentsMap.put((String) header[0], header[1]); - } - else if (annotation.annotationType().equals(Payload.class)) { - // need to clarify what to do here - throw new IllegalArgumentException("@Payload is not allowed when mapping from method to Message"); + mappedMessageOrPayload = true; } } - Assert.isTrue(payloadExist, "Payload can not be determined from method: " + method); + Assert.isTrue(mappedMessageOrPayload, "Payload can not be determined from method: " + method); return messageArgumentsMap; } @@ -297,8 +297,8 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper message, MethodParameter methodParameter, Object headerValue) { String valueAttribute = (String) AnnotationUtils.getValue(header); String headerName = StringUtils.hasText(valueAttribute) ? valueAttribute : methodParameter.getParameterName(); - Assert.notNull(headerName, "Can not determine header name. Possible reasons: -debug is " + - "disabled or header name is not explicitly provided via @Header annotation"); + Assert.notNull(headerName, "Cannot determine header name. Possible reasons: -debug is " + + "disabled or header name is not explicitly provided via @Header annotation."); if (message != null) { headerValue = this.getValueFromMessageBasedOnEL(message, methodParameter.getParameterType(), false, "headers." + headerName); } @@ -322,17 +322,19 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapperProperties conversion + if (value != null && this.canConvertToType(value, targetType)) { + // to accommodate Map->Properties conversion + value = expression.equals("headers") ? conversionService.convert(value, targetType) : value; break; } else { value = null; - } + } } catch (Throwable e) { if (rethrowException) { @@ -356,28 +358,31 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper message) { // validate against maps with no annotations - int counterOfUnnamedMapAttributes = 0; + public void validateMessageMapppings(Message message) { + // Validate against a Map with no annotations if (message.getPayload() instanceof Map) { + boolean foundOneMatch = false; for (MethodParameter parameter : this.parameterList) { - if ( parameter.getParameterAnnotations().length == 0 && - (parameter.getParameterType().isAssignableFrom(Properties.class) || parameter.getParameterType().isAssignableFrom(Map.class)) && - !(parameter.getParameterName().equals("payload") || parameter.getParameterName().equals("headers")) ) { - counterOfUnnamedMapAttributes++; + String name = parameter.getParameterName(); + Class type = parameter.getParameterType(); + if (parameter.getParameterAnnotations().length == 0 && + !(name.equals("payload") || name.equals("headers")) && + (type.isAssignableFrom(Properties.class) || type.isAssignableFrom(Map.class))) { + if (foundOneMatch) { + throw new IllegalArgumentException("Ambiguous parameters. " + + "Cannot determine parameter mappings between Method: [" + method + "] and Message: " + message + + ". Try annotating individual parameters with @Payload, @Header, or @Headers"); + } + foundOneMatch = true; } } - if (counterOfUnnamedMapAttributes > 1) { - throw new IllegalArgumentException("Ambiguous parameters. Can not determine parameter mappings between Method: " + method + - " and Message: " + message + - ". Try annotating individual parameters with @Headers, @Header or @MessageMapping"); - } } }