Repository: camel Updated Branches: refs/heads/master 2be65c116 -> f554c483e
CAMEL-10424: Bean should act like transform/setBody when setting result Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/36bcdc87 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/36bcdc87 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/36bcdc87 Branch: refs/heads/master Commit: 36bcdc87bdcb2e214b2150bf430f181d3c93458b Parents: 2be65c1 Author: Claus Ibsen <davscl...@apache.org> Authored: Sat Oct 29 12:31:15 2016 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sat Oct 29 12:31:15 2016 +0200 ---------------------------------------------------------------------- .../apache/camel/component/bean/MethodInfo.java | 56 ++++++++---- .../BeanProcessorSpecializedMessageTest.java | 93 ++++++++++++++++++++ 2 files changed, 133 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/36bcdc87/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java b/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java index 532046b..41fe76c 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java @@ -37,17 +37,20 @@ import org.apache.camel.Exchange; import org.apache.camel.ExchangePattern; import org.apache.camel.Expression; import org.apache.camel.ExpressionEvaluationException; +import org.apache.camel.Message; import org.apache.camel.NoTypeConversionAvailableException; import org.apache.camel.Pattern; import org.apache.camel.Processor; import org.apache.camel.RuntimeExchangeException; import org.apache.camel.StreamCache; +import org.apache.camel.impl.DefaultMessage; import org.apache.camel.processor.DynamicRouter; import org.apache.camel.processor.RecipientList; import org.apache.camel.processor.RoutingSlip; import org.apache.camel.processor.aggregate.AggregationStrategy; import org.apache.camel.support.ExpressionAdapter; import org.apache.camel.util.CamelContextHelper; +import org.apache.camel.util.ExchangeHelper; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ServiceHelper; import org.apache.camel.util.StringHelper; @@ -116,15 +119,15 @@ public class MethodInfo { this.hasCustomAnnotation = hasCustomAnnotation; this.hasHandlerAnnotation = hasHandlerAnnotation; this.parametersExpression = createParametersExpression(); - + Map<Class<?>, Annotation> collectedMethodAnnotation = collectMethodAnnotations(type, method); Pattern oneway = findOneWayAnnotation(method); if (oneway != null) { pattern = oneway.value(); } - - org.apache.camel.RoutingSlip routingSlipAnnotation = + + org.apache.camel.RoutingSlip routingSlipAnnotation = (org.apache.camel.RoutingSlip)collectedMethodAnnotation.get(org.apache.camel.RoutingSlip.class); if (routingSlipAnnotation != null && matchContext(routingSlipAnnotation.context())) { routingSlip = new RoutingSlip(camelContext); @@ -138,7 +141,7 @@ public class MethodInfo { } } - org.apache.camel.DynamicRouter dynamicRouterAnnotation = + org.apache.camel.DynamicRouter dynamicRouterAnnotation = (org.apache.camel.DynamicRouter)collectedMethodAnnotation.get(org.apache.camel.DynamicRouter.class); if (dynamicRouterAnnotation != null && matchContext(dynamicRouterAnnotation.context())) { @@ -153,7 +156,7 @@ public class MethodInfo { } } - org.apache.camel.RecipientList recipientListAnnotation = + org.apache.camel.RecipientList recipientListAnnotation = (org.apache.camel.RecipientList)collectedMethodAnnotation.get(org.apache.camel.RecipientList.class); if (recipientListAnnotation != null && matchContext(recipientListAnnotation.context())) { @@ -201,7 +204,7 @@ public class MethodInfo { collectMethodAnnotations(c, method, annotations); return annotations; } - + private void collectMethodAnnotations(Class<?> c, Method method, Map<Class<?>, Annotation> annotations) { for (Class<?> i : c.getInterfaces()) { collectMethodAnnotations(i, method, annotations); @@ -337,16 +340,37 @@ public class MethodInfo { } private void fillResult(Exchange exchange, Object result) { - if (exchange.getPattern().isOutCapable()) { - // force out creating if not already created (as its lazy) - LOG.debug("Setting bean invocation result on the OUT message: {}", result); - exchange.getOut().setBody(result); + LOG.trace("Setting bean invocation result : {}", result); + + // the bean component forces OUT if the MEP is OUT capable + boolean out = ExchangeHelper.isOutCapable(exchange) || exchange.hasOut(); + Message old; + if (out) { + old = exchange.getOut(); // propagate headers exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders()); + // propagate attachments + if (exchange.getIn().hasAttachments()) { + exchange.getOut().getAttachments().putAll(exchange.getIn().getAttachments()); + } } else { - // if not out then set it on the in - LOG.debug("Setting bean invocation result on the IN message: {}", result); - exchange.getIn().setBody(result); + old = exchange.getIn(); + } + + // create a new message container so we do not drag specialized message objects along + // but that is only needed if the old message is a specialized message + boolean copyNeeded = !(old.getClass().equals(DefaultMessage.class)); + + if (copyNeeded) { + Message msg = new DefaultMessage(); + msg.copyFrom(old); + msg.setBody(result); + + // replace message on exchange + ExchangeHelper.replaceMessage(exchange, msg, false); + } else { + // no copy needed so set replace value directly + old.setBody(result); } } @@ -417,16 +441,16 @@ public class MethodInfo { public boolean isStaticMethod() { return Modifier.isStatic(method.getModifiers()); } - + /** * Returns true if this method is covariant with the specified method * (this method may above or below the specified method in the class hierarchy) */ public boolean isCovariantWith(MethodInfo method) { - return + return method.getMethod().getName().equals(this.getMethod().getName()) && (method.getMethod().getReturnType().isAssignableFrom(this.getMethod().getReturnType()) - || this.getMethod().getReturnType().isAssignableFrom(method.getMethod().getReturnType())) + || this.getMethod().getReturnType().isAssignableFrom(method.getMethod().getReturnType())) && Arrays.deepEquals(method.getMethod().getParameterTypes(), this.getMethod().getParameterTypes()); } http://git-wip-us.apache.org/repos/asf/camel/blob/36bcdc87/camel-core/src/test/java/org/apache/camel/processor/BeanProcessorSpecializedMessageTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/processor/BeanProcessorSpecializedMessageTest.java b/camel-core/src/test/java/org/apache/camel/processor/BeanProcessorSpecializedMessageTest.java new file mode 100644 index 0000000..6e86328 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/processor/BeanProcessorSpecializedMessageTest.java @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.processor; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.Predicate; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.DefaultMessage; + +/** + * @version + */ +public class BeanProcessorSpecializedMessageTest extends ContextTestSupport { + + public void testBeanSpecializedMessage() throws Exception { + MockEndpoint foo = getMockEndpoint("mock:foo"); + foo.expectedBodiesReceived("Hello World"); + foo.expectedHeaderReceived("foo", 123); + foo.message(0).predicate(new Predicate() { + public boolean matches(Exchange exchange) { + // this time we should have the specialized message + return exchange.getIn() instanceof MyMessage; + } + }); + + MockEndpoint result = getMockEndpoint("mock:result"); + result.message(0).body().isNull(); + result.expectedHeaderReceived("foo", 123); + result.message(0).predicate(new Predicate() { + public boolean matches(Exchange exchange) { + // this time we should have lost the specialized message + return !(exchange.getIn() instanceof MyMessage); + } + }); + + template.send("direct:start", new Processor() { + public void process(Exchange exchange) throws Exception { + MyMessage my = new MyMessage(); + my.setBody("Hello World"); + my.setHeader("foo", 123); + exchange.setIn(my); + } + }); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .to("mock:foo") + .bean(MyBean.class, "empty") + .to("mock:result"); + } + }; + } + + public static class MyMessage extends DefaultMessage { + + @Override + public MyMessage newInstance() { + return new MyMessage(); + } + } + + public static class MyBean { + + public static String empty(String body) { + // set null as body + return null; + } + } +}