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 53cb8810ca..10bb0d0f1b 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 @@ -25,6 +25,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -33,7 +35,6 @@ 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.message.OutboundMessageMapper; import org.springframework.integration.util.DefaultMethodInvoker; import org.springframework.integration.util.MethodInvoker; import org.springframework.util.Assert; @@ -54,17 +55,17 @@ public class MessageMappingMethodInvoker implements MessageProcessor { protected static final Log logger = LogFactory.getLog(MessageMappingMethodInvoker.class); - private final Set methodsExpectingMessage = new HashSet(); - private volatile Object object; private final HandlerMethodResolver methodResolver; - private final Map> messageMappers = - new HashMap>(); + private final ConcurrentMap messageMappers = + new ConcurrentHashMap(); private final Map invokers = new HashMap(); + private final Set methodsExpectingMessage = new HashSet(); + public MessageMappingMethodInvoker(Object object, Method method) { Assert.notNull(object, "object must not be null"); @@ -102,7 +103,12 @@ public class MessageMappingMethodInvoker implements MessageProcessor { Method method = this.methodResolver.resolveHandlerMethod(message); Object[] args = null; try { - args = this.createArgumentArrayFromMessage(method, message); + if (this.methodsExpectingMessage.contains(method)) { + args = new Object[] { message }; + } + else { + args = this.resolveMessageMapper(method).fromMessage(message); + } return this.invokeMethod(method, args, message); } catch (InvocationTargetException e) { @@ -168,45 +174,6 @@ public class MessageMappingMethodInvoker implements MessageProcessor { return result; } - private Object[] createArgumentArrayFromMessage(Method method, Message message) throws Exception { - Object args[] = null; - Object mappingResult = this.methodsExpectingMessage.contains(method) - ? message : this.resolveParameters(method, 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; - for (int i = 0; i < args.length; i++) { - Object arg = args[i]; - if (arg instanceof Map && Map.class.isAssignableFrom(method.getParameterTypes()[i])) { - mapArgCount++; - if (arg.equals(message.getPayload())) { - // resolved if there is exactly one match - resolvedMapArg = !resolvedMapArg; - } - } - } - Assert.isTrue(resolvedMapArg || mapArgCount <= 1, - "Unable to resolve argument for Map-typed payload on method [" + method + "]."); - } - return args; - } - - private Object[] resolveParameters(Method method, Message message) throws Exception { - OutboundMessageMapper mapper = this.messageMappers.get(method); - if (mapper == null) { - mapper = new MethodParameterMessageMapper(method); - this.messageMappers.put(method, mapper); - } - return mapper.fromMessage(message); - } - private HandlerMethodResolver createResolverForMethodName(String methodName, boolean requiresReturnValue) { List methodsWithName = new ArrayList(); Method[] defaultCandidateMethods = HandlerMethodUtils.getCandidateHandlerMethods(this.object); @@ -249,4 +216,17 @@ public class MessageMappingMethodInvoker implements MessageProcessor { return new PayloadTypeMatchingHandlerMethodResolver(candidateMethods); } + private MethodArgumentMessageMapper resolveMessageMapper(Method method) { + MethodArgumentMessageMapper mapper = this.messageMappers.get(method); + if (mapper == null) { + mapper = new MethodArgumentMessageMapper(method); + MethodArgumentMessageMapper existingMapper = this.messageMappers.putIfAbsent(method, mapper); + if (existingMapper != null) { + // throw away the one just created, since one was created in the meantime + mapper = existingMapper; + } + } + return mapper; + } + } 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 new file mode 100644 index 0000000000..18b0a839ab --- /dev/null +++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/MethodArgumentMessageMapper.java @@ -0,0 +1,75 @@ +/* + * 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.handler; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.springframework.integration.core.Message; +import org.springframework.integration.message.MethodParameterMessageMapper; +import org.springframework.integration.message.OutboundMessageMapper; +import org.springframework.util.Assert; + +/** + * @author Mark Fisher + * @since 2.0 + */ +public class MethodArgumentMessageMapper implements OutboundMessageMapper { + + private final Method method; + + //TODO: move core mapping logic from MethodParameterMessageMapper into this class + private final MethodParameterMessageMapper innerMapper; + + + public MethodArgumentMessageMapper(Method method) { + Assert.notNull(method, "method must not be null"); + this.method = method; + this.innerMapper = new MethodParameterMessageMapper(method); + } + + + public Object[] fromMessage(Message message) throws Exception { + Object args[] = null; + Object mappingResult = this.innerMapper.fromMessage(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; + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (arg instanceof Map && Map.class.isAssignableFrom(method.getParameterTypes()[i])) { + mapArgCount++; + if (arg.equals(message.getPayload())) { + // resolved if there is exactly one match + resolvedMapArg = !resolvedMapArg; + } + } + } + Assert.isTrue(resolvedMapArg || mapArgCount <= 1, + "Unable to resolve argument for Map-typed payload on method [" + method + "]."); + } + return args; + } + +}