MMIH: Convert from JSON only if SpELInvoker
If there is `json`-aware `contentType` header in the message to process and payload type is `String` or `byte[]` and it isn't equal to the expected exclusive method argument type (even generic from the `Message<>`), the conversion should happen only if SpelInvoker is no method. The regular `InvocableHandlerMethod` takes care about payload conversion via configured `MessageConverter` in the `PayloadArgumentResolver` * Fix `MessagingMethodInvokerHelper` to call JSON conversion only when `this.handlerMethod.spelOnly` NOTE: We can't do generics conversion right now because it is going to be a breaking change around `org.springframework.integration.support.json.JsonObjectMapper` property in the `MessagingMethodInvokerHelper`. We can do that only in `5.1` and rely there only on the functionality from the Jackson Object mapper * Convert from JSON only in the `invokeExpression()` * Optimize message recreation only if target param type is `Message`. Otherwise override just `payload` property of the `ParametersWrapper`
This commit is contained in:
committed by
Gary Russell
parent
60606dd6fe
commit
2c3ee7d68c
@@ -308,46 +308,10 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
}
|
||||
|
||||
public T process(Message<?> message) throws Exception {
|
||||
Message<?> messageToProcess = possiblyConvert(message);
|
||||
ParametersWrapper parameters = new ParametersWrapper(messageToProcess);
|
||||
ParametersWrapper parameters = new ParametersWrapper(message);
|
||||
return processInternal(parameters);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's a single method, the content is JSON, the payload is a
|
||||
* String or byte[], the parameter doesn't match the payload,
|
||||
* and there is a Json Object Mapper on the CP,
|
||||
* convert.
|
||||
*/
|
||||
private Message<?> possiblyConvert(Message<?> message) throws Exception {
|
||||
if (this.handlerMethod != null && this.handlerMethod.getTargetParameterType() != null &&
|
||||
this.jsonObjectMapper != null) {
|
||||
Class<?> type = this.handlerMethod.getTargetParameterType();
|
||||
if ((message.getPayload() instanceof String && !type.equals(String.class)
|
||||
|| message.getPayload() instanceof byte[] && !type.equals(byte[].class))
|
||||
&& contentTypeIsJson(message)) {
|
||||
|
||||
try {
|
||||
return getMessageBuilderFactory()
|
||||
.withPayload(this.jsonObjectMapper.fromJson(message.getPayload(), type))
|
||||
.copyHeaders(message.getHeaders())
|
||||
.build();
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to convert from JSON", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private boolean contentTypeIsJson(Message<?> message) {
|
||||
Object contentType = message.getHeaders().get(MessageHeaders.CONTENT_TYPE);
|
||||
return contentType != null && contentType.toString().contains("json");
|
||||
}
|
||||
|
||||
public T process(Collection<Message<?>> messages, Map<String, Object> headers) throws Exception {
|
||||
ParametersWrapper parameters = new ParametersWrapper(messages, headers);
|
||||
return processInternal(parameters);
|
||||
@@ -645,6 +609,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
@SuppressWarnings("unchecked")
|
||||
private T invokeExpression(Expression expression, ParametersWrapper parameters) throws Exception {
|
||||
try {
|
||||
|
||||
convertJsonPayloadIfNecessary(parameters);
|
||||
return (T) evaluateExpression(expression, parameters);
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -662,6 +628,52 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's a single method, it is SpEL only, the content is JSON,
|
||||
* the payload is a String or byte[], the parameter doesn't match the payload,
|
||||
* and there is a Json Object Mapper on the CP, convert.
|
||||
*/
|
||||
private void convertJsonPayloadIfNecessary(ParametersWrapper parameters) {
|
||||
if (parameters.message != null &&
|
||||
this.handlerMethod != null &&
|
||||
this.handlerMethod.exclusiveMethodParameter != null &&
|
||||
this.jsonObjectMapper != null) {
|
||||
|
||||
Class<?> type = this.handlerMethod.targetParameterType;
|
||||
if ((parameters.getPayload() instanceof String && !type.equals(String.class)
|
||||
|| parameters.getPayload() instanceof byte[] && !type.equals(byte[].class))
|
||||
&& contentTypeIsJson(parameters.message)) {
|
||||
|
||||
try {
|
||||
Object targetPayload = this.jsonObjectMapper.fromJson(parameters.getPayload(), type);
|
||||
|
||||
if (this.handlerMethod.targetParameterTypeDescriptor.isAssignableTo(messageTypeDescriptor)) {
|
||||
parameters.message =
|
||||
getMessageBuilderFactory()
|
||||
.withPayload(targetPayload)
|
||||
.copyHeaders(parameters.getHeaders())
|
||||
.build();
|
||||
}
|
||||
else {
|
||||
parameters.payload = targetPayload;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to convert from JSON", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean contentTypeIsJson(Message<?> message) {
|
||||
Object contentType = message.getHeaders().get(MessageHeaders.CONTENT_TYPE);
|
||||
return contentType != null && contentType.toString().contains("json");
|
||||
}
|
||||
|
||||
private Map<String, Map<Class<?>, HandlerMethod>> findHandlerMethodsForTarget(final Object targetObject,
|
||||
final Class<? extends Annotation> annotationType, final String methodName, final boolean requiresReply) {
|
||||
|
||||
@@ -1013,6 +1025,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
|
||||
private volatile Class<?> targetParameterType = Void.class;
|
||||
|
||||
private MethodParameter exclusiveMethodParameter;
|
||||
|
||||
private volatile boolean messageMethod;
|
||||
|
||||
private volatile boolean spelOnly;
|
||||
@@ -1220,6 +1234,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
|
||||
private void setExclusiveTargetParameterType(TypeDescriptor targetParameterType,
|
||||
MethodParameter methodParameter) {
|
||||
|
||||
if (this.targetParameterTypeDescriptor != null) {
|
||||
throw new IneligibleMethodException("Found more than one parameter type candidate: [" +
|
||||
this.targetParameterTypeDescriptor + "] and [" + targetParameterType + "]");
|
||||
@@ -1233,18 +1248,20 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
else {
|
||||
this.targetParameterType = targetParameterType.getObjectType();
|
||||
}
|
||||
|
||||
this.exclusiveMethodParameter = methodParameter;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParametersWrapper {
|
||||
|
||||
private final Object payload;
|
||||
|
||||
private final Collection<Message<?>> messages;
|
||||
|
||||
private final Map<String, Object> headers;
|
||||
|
||||
private final Message<?> message;
|
||||
private Message<?> message;
|
||||
|
||||
private Object payload;
|
||||
|
||||
ParametersWrapper(Message<?> message) {
|
||||
this.message = message;
|
||||
@@ -1254,10 +1271,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
}
|
||||
|
||||
ParametersWrapper(Collection<Message<?>> messages, Map<String, Object> headers) {
|
||||
this.payload = null;
|
||||
this.messages = messages;
|
||||
this.headers = headers;
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1017,7 +1017,12 @@ public class MethodInvokingMessageProcessorTests {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
byte[] value = objectMapper.writeValueAsBytes(testData);
|
||||
|
||||
String result = (String) processor.processMessage(new GenericMessage<>(value));
|
||||
Message<?> testMessage =
|
||||
MessageBuilder.withPayload(value)
|
||||
.setHeader(MessageHeaders.CONTENT_TYPE, "application/json")
|
||||
.build();
|
||||
|
||||
String result = (String) processor.processMessage(testMessage);
|
||||
|
||||
assertEquals("Foo,Bar", result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user