INT-681, INT-710 started to refactor message-mapping logic to support EL, etc.

This commit is contained in:
Mark Fisher
2009-09-29 15:11:14 +00:00
parent 2165fdbe1e
commit 047b31d759
2 changed files with 100 additions and 45 deletions

View File

@@ -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<Method> methodsExpectingMessage = new HashSet<Method>();
private volatile Object object;
private final HandlerMethodResolver methodResolver;
private final Map<Method, OutboundMessageMapper<Object[]>> messageMappers =
new HashMap<Method, OutboundMessageMapper<Object[]>>();
private final ConcurrentMap<Method, MethodArgumentMessageMapper> messageMappers =
new ConcurrentHashMap<Method, MethodArgumentMessageMapper>();
private final Map<Method, MethodInvoker> invokers = new HashMap<Method, MethodInvoker>();
private final Set<Method> methodsExpectingMessage = new HashSet<Method>();
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<Object[]> 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<Method> methodsWithName = new ArrayList<Method>();
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;
}
}

View File

@@ -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<Object[]> {
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;
}
}