camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Camel > Bean Binding
Date Tue, 26 Jul 2011 06:54:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CAMEL&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CAMEL/Bean+Binding">Bean
Binding</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~davsclaus">Claus
Ibsen</a>
    </h4>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{tip} <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Besides
the message body, you can pass in the message headers as a {{java.util.Map}} type, and declare
it as follows: <br>{code} <br>   .bean(OrderService.class, &quot;doSomethingWithHeaders(${body},
${headers})&quot;) <br>{code} <br> <br></td></tr>
            <tr><td class="diff-unchanged" >You can also pass in other fixed values
than boolean values. For example to pass in an String and integer do as follows: <br>{code}
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h2><a name="BeanBinding-BeanBinding"></a>Bean Binding</h2>

<p>The Bean Binding in Camel defines both which methods are invoked and also how the
<a href="/confluence/display/CAMEL/Message" title="Message">Message</a> is converted
into the parameters of the method when it is invoked.</p>

<h3><a name="BeanBinding-Choosingthemethodtoinvoke"></a>Choosing the method
to invoke</h3>

<p>The binding of a Camel <a href="/confluence/display/CAMEL/Message" title="Message">Message</a>
to a bean method call can occur in different ways, order if importance:</p>

<ul>
	<li>if the message contains the header <b>CamelBeanMethodName</b> then
that method is invoked, converting the body to whatever the argument is to the method.
	<ul>
		<li>From <b>Camel 2.8</b> onwards you can qualify parameter types to exact
pin-point which method to use when using overloaded methods with the same name (see further
below for more details).</li>
		<li>From <b>Camel 2.9</b> onwards you can specify parameter values directly
in the method option (see further below for more details).</li>
	</ul>
	</li>
	<li>the method name can be specified explicitly in the <a href="/confluence/display/CAMEL/DSL"
title="DSL">DSL</a> or when using <a href="/confluence/display/CAMEL/POJO+Consuming"
title="POJO Consuming">POJO Consuming</a> or <a href="/confluence/display/CAMEL/POJO+Producing"
title="POJO Producing">POJO Producing</a></li>
	<li>if the bean has a method that is marked with <tt>@Handler</tt> annotation
then that method is selected</li>
	<li>if the bean can be converted to a <a href="/confluence/display/CAMEL/Processor"
title="Processor">Processor</a> using the <a href="/confluence/display/CAMEL/Type+Converter"
title="Type Converter">Type Converter</a> mechanism then this is used to process
the message. This mechanism is used by the <a href="/confluence/display/CAMEL/ActiveMQ"
title="ActiveMQ">ActiveMQ</a> component to allow any JMS MessageListener to be invoked
directly by Camel without having to write any integration glue code. You can use the same
mechanism to integrate Camel into any other messaging/remoting frameworks.</li>
	<li>if the body of the message can be converted to a <a href="http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/bean/BeanInvocation.html"
class="external-link" rel="nofollow">BeanInvocation</a> (the default payload used
by the <a href="http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/component/bean/ProxyHelper.html"
class="external-link" rel="nofollow">ProxyHelper</a>) - then that its used to invoke
the method and pass the arguments</li>
	<li>otherwise the type of the method body is used to try find a method which matches;
an error is thrown if a single method cannot be chosen unambiguously.</li>
	<li>you can also use Exchange as the parameter itself, but then the return type must
be void.</li>
</ul>


<p>In case where Camel will not be able to choose a method to invoke an <tt>AmbiguousMethodCallException</tt>
is thrown. </p>

<p>By default the return value is set on the outbound message body.</p>


<h3><a name="BeanBinding-Parameterbinding"></a>Parameter binding</h3>
<p>When a method have been chosen to be invoked Camel will bind to the parameters of
the method.</p>

<p>The following Camel specific types is automatic binded:</p>
<ul class="alternate" type="square">
	<li><tt>org.apache.camel.Exchange</tt></li>
	<li><tt>org.apache.camel.Message</tt></li>
	<li><tt>org.apache.camel.CamelContext</tt></li>
	<li><tt>org.apache.camel.TypeConverter</tt></li>
	<li><tt>org.apache.camel.spi.Registry</tt></li>
	<li><tt>java.lang.Exception</tt></li>
</ul>


<p>So if you declare any of the given type above they will be provided by Camel. A <b>note</b>
on the <tt>Exception</tt> is that it will bind to the caught exception of the
<a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a>. So
its often usable if you use a <a href="/confluence/display/CAMEL/Pojo" title="Pojo">Pojo</a>
to handle a given using using eg an <tt>onException</tt> route. </p>

<p>What is most interresting is that Camel will also try to bind the body of the <a
href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a> to the first
parameter of the method signature (albeit not of any of the types above). So if we for instance
declare e parameter as: <tt>String body</tt> then Camel will bind the IN body
to this type. Camel will also automatic type convert to the given type declared.</p>

<p>Okay lets show some examples.</p>

<p>Below is just a simple method with a body binding. Camel will bind the IN body to
the <tt>body</tt> parameter and convert it to a <tt>String</tt> type.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-object">String</span>
doSomething(<span class="code-object">String</span> body)
</pre>
</div></div>

<p>And in this sample we got one of the automatic binded type as well, for instance
the <tt>Registry</tt> that we can use to lookup beans.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-object">String</span>
doSomething(<span class="code-object">String</span> body, Registry registry)
</pre>
</div></div>

<p>And we can also use <a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a>
as well:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-object">String</span>
doSomething(<span class="code-object">String</span> body, Exchange exchange)
</pre>
</div></div>

<p>You can have multiple types as well</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-object">String</span>
doSomething(<span class="code-object">String</span> body, Exchange exchange, TypeConverter
converter)
</pre>
</div></div>

<p>And imagine you use a <a href="/confluence/display/CAMEL/Pojo" title="Pojo">Pojo</a>
to handle a given custom exception <tt>InvalidOrderException</tt> then we can
bind that as well:<br/>
Notice we can bind to it even if we use a sub type of <tt>java.lang.Exception</tt>
as Camel still knows its an exception and thus can bind the caused exception (if any exists).</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-object">String</span>
badOrder(<span class="code-object">String</span> body, InvalidOrderException invalid)
</pre>
</div></div>

<p>So what about headers and other stuff? Well now it gets a bit tricky so we can use
annotations to help us, or specify the binding in the method name option.<br/>
See the following sections for more details.</p>

<h3><a name="BeanBinding-BindingAnnotations"></a>Binding Annotations</h3>

<p>You can use the <a href="/confluence/display/CAMEL/Parameter+Binding+Annotations"
title="Parameter Binding Annotations">Parameter Binding Annotations</a> to customize
how parameter values are created from the <a href="/confluence/display/CAMEL/Message" title="Message">Message</a></p>

<h4><a name="BeanBinding-Examples"></a>Examples</h4>

<p>For example a <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a>
such as:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class Bar {

    <span class="code-keyword">public</span> <span class="code-object">String</span>
doSomething(<span class="code-object">String</span> body) {
      <span class="code-comment">// process the in body and <span class="code-keyword">return</span>
whatever you want
</span>      <span class="code-keyword">return</span> <span class="code-quote">"Bye
World"</span>;
   }
</pre>
</div></div>

<p>Or the Exchange example. Notice that the return type must be <b>void</b>
when there is only a single parameter:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class Bar {

    <span class="code-keyword">public</span> void doSomething(Exchange exchange)
{
      <span class="code-comment">// process the exchange
</span>      exchange.getIn().setBody(<span class="code-quote">"Bye World"</span>);
   }
</pre>
</div></div>

<h4><a name="BeanBinding-@Handler"></a>@Handler</h4>
<p>You can mark a method in your bean with the @Handler annotation to indicate that
this method should be used for <a href="/confluence/display/CAMEL/Bean+Binding" title="Bean
Binding">Bean Binding</a>.<br/>
This has the advantage as you do not have to specify the method name in the Camel route. And
thus you do not run into problems when you rename the method name using an IDE that don't
find all references.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class Bar {

    @Handler
    <span class="code-keyword">public</span> <span class="code-object">String</span>
doSomething(<span class="code-object">String</span> body) {
      <span class="code-comment">// process the in body and <span class="code-keyword">return</span>
whatever you want
</span>      <span class="code-keyword">return</span> <span class="code-quote">"Bye
World"</span>;
   }
</pre>
</div></div>


<h3><a name="BeanBinding-Parameterbindingusingmethodoption"></a>Parameter
binding using method option</h3>
<p><b>Available as of Camel 2.9</b></p>

<p>Camel uses the following rules to determine if its a parameter value in the method
option</p>
<ul class="alternate" type="square">
	<li>The value is either <tt>true</tt> or <tt>false</tt> which
denotes a boolean value</li>
	<li>The value is a numeric value such as <tt>123</tt> or <tt>7</tt></li>
	<li>The value is a String enclosed with either single or double quotes</li>
	<li>It can be evaluated using the <a href="/confluence/display/CAMEL/Simple" title="Simple">Simple</a>
language, which means you can use eg body, header.foo and other <a href="/confluence/display/CAMEL/Simple"
title="Simple">Simple</a> tokens.</li>
</ul>


<p>Any other value is consider to be a type declaration instead, see next section about
pin pointing types for overloaded methods.</p>

<p>When invoking a <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a>
you can instruct Camel to invoke a specific method by providing the method name. For example
as shown below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething"</span>)
</pre>
</div></div>

<p>Here we tell Camel to invoke the doSomething method. How the parameters is bound
is handled by Camel. Now suppose the method has 2 parameters, and the 2nd parameter is a boolean,
where we want to pass in a true value, such as the method signature below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> void doSomething(<span class="code-object">String</span>
payload, <span class="code-object">boolean</span> highPriority) {
   ...
}
</pre>
</div></div>

<p>This is now possible in <b>Camel 2.9</b> onwards:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething(*, <span class="code-keyword">true</span>)"</span>)
</pre>
</div></div>

<p>In the example above, we defined the first parameter using the wild card symbol *,
which tells Camel to bind this parameter to any type, and let Camel figure this out. The 2nd
parameter has a fixed value of <tt>true</tt>. Instead of the wild card symbol
we can instruct Camel to use the message body as shown:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething(body, <span class="code-keyword">true</span>)"</span>)
</pre>
</div></div>

<p>The syntax of the parameters is using the <a href="/confluence/display/CAMEL/Simple"
title="Simple">Simple</a> expression language so we can use ${ } placeholders to
make this more expressive:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething(${body}, <span
class="code-keyword">true</span>)"</span>)
</pre>
</div></div>

<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/check.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td>Its a good idea to use ${ } placeholders
in the method option as shown in the example above. This makes it clear to the read, that
this is a <a href="/confluence/display/CAMEL/Simple" title="Simple">Simple</a>
token and the actual value is dynamic computed form the <a href="/confluence/display/CAMEL/Exchange"
title="Exchange">Exchange</a> being routed.</td></tr></table></div>

<p>Besides the message body, you can pass in the message headers as a <tt>java.util.Map</tt>
type, and declare it as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomethingWithHeaders(${body},
${headers})"</span>)
</pre>
</div></div>

<p>You can also pass in other fixed values than boolean values. For example to pass
in an String and integer do as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(MyBean.class, <span class="code-quote">"echo('World', 5)"</span>)
</pre>
</div></div>
<p>In the example above, we invoke the echo method with two parameters. The first has
the content 'World' (without the quotes). And the 2nd the value of 5.<br/>
Camel will automatic type convert the values to the parameter types.</p>

<p>Having the power of the <a href="/confluence/display/CAMEL/Simple" title="Simple">Simple</a>
language allows us to bind to message headers and other values such as:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething(${body}, ${header.high})"</span>)
</pre>
</div></div>

<p>You can also use the OGNL support of the <a href="/confluence/display/CAMEL/Simple"
title="Simple">Simple</a> expression language. Now suppose the message body is an
object which has a method named <tt>asXml</tt>. To invoke the <tt>asXml</tt>
method we can do as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething(${body.asXml}, ${header.high})"</span>)
</pre>
</div></div>

<p>Instead of using <tt>.bean</tt> as shown in the examples above, you may
want to use <tt>.to</tt> instead as shown:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .to(<span class="code-quote">"bean:orderService?method=doSomething(${body.asXml},
${header.high})"</span>)
</pre>
</div></div>


<h3><a name="BeanBinding-Usingtypequalifiertopinpointmethodtousewhenhavingoverloadedmethods"></a>Using
type qualifier to pin-point method to use when having overloaded methods</h3>
<p><b>Available as of Camel 2.8</b></p>

<p>If you have a <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a>
which has overloaded methods you can now specify the parameter types in the method name, so
Camel can match the method you intend to use.<br/>
Given the following bean:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>MyBean</b></div><div class="codeContent
panelContent">
<pre class="code-java"><span class="code-keyword">public</span> <span
class="code-keyword">static</span> <span class="code-keyword">final</span>
class MyBean {

    <span class="code-keyword">public</span> <span class="code-object">String</span>
hello(<span class="code-object">String</span> name) {
        <span class="code-keyword">return</span> <span class="code-quote">"Hello
"</span> + name;
    }

    <span class="code-keyword">public</span> <span class="code-object">String</span>
hello(<span class="code-object">String</span> name, @Header(<span class="code-quote">"country"</span>)
<span class="code-object">String</span> country) {
        <span class="code-keyword">return</span> <span class="code-quote">"Hello
"</span> + name + <span class="code-quote">" you are from "</span> + country;
    }

    <span class="code-keyword">public</span> <span class="code-object">String</span>
times(<span class="code-object">String</span> name, @Header(<span class="code-quote">"times"</span>)
<span class="code-object">int</span> times) {
        StringBuilder sb = <span class="code-keyword">new</span> StringBuilder();
        <span class="code-keyword">for</span> (<span class="code-object">int</span>
i = 0; i &lt; times; i++) {
            sb.append(name);
        }
        <span class="code-keyword">return</span> sb.toString();
    }

    <span class="code-keyword">public</span> <span class="code-object">String</span>
times(<span class="code-object">byte</span>[] data, @Header(<span class="code-quote">"times"</span>)
<span class="code-object">int</span> times) {
        <span class="code-object">String</span> s = <span class="code-keyword">new</span>
<span class="code-object">String</span>(data);
        StringBuilder sb = <span class="code-keyword">new</span> StringBuilder();
        <span class="code-keyword">for</span> (<span class="code-object">int</span>
i = 0; i &lt; times; i++) {
            sb.append(s);
            <span class="code-keyword">if</span> (i &lt; times - 1) {
                sb.append(<span class="code-quote">","</span>);
            }
        }
        <span class="code-keyword">return</span> sb.toString();
    }

    <span class="code-keyword">public</span> <span class="code-object">String</span>
times(<span class="code-object">String</span> name, <span class="code-object">int</span>
times, <span class="code-object">char</span> separator) {
        StringBuilder sb = <span class="code-keyword">new</span> StringBuilder();
        <span class="code-keyword">for</span> (<span class="code-object">int</span>
i = 0; i &lt; times; i++) {
            sb.append(name);
            <span class="code-keyword">if</span> (i &lt; times - 1) {
                sb.append(separator);
            }
        }
        <span class="code-keyword">return</span> sb.toString();
    }

}
</pre>
</div></div>

<p>Then the <tt>MyBean</tt> has 2 overloaded methods with the names <tt>hello</tt>
and <tt>times</tt>. So if we want to use the method which has 2 parameters we
can do as follows in the Camel route:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Invoke 2 parameter method</b></div><div
class="codeContent panelContent">
<pre class="code-java">from(<span class="code-quote">"direct:start"</span>)
    .bean(MyBean.class, <span class="code-quote">"hello(<span class="code-object">String</span>,<span
class="code-object">String</span>)"</span>)
    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>We can also use a <tt>*</tt> as wildcard so we can just say we want to
execute the method with 2 parameters we do</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Invoke 2 parameter method using wildcard</b></div><div
class="codeContent panelContent">
<pre class="code-java">from(<span class="code-quote">"direct:start"</span>)
    .bean(MyBean.class, <span class="code-quote">"hello(*,*)"</span>)
    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>By default Camel will match the type name using the simple name, eg any leading package
name will be disregarded. However if you want to match using the FQN then specify the FQN
type and Camel will leverage that. So if you have a <tt>com.foo.MyOrder</tt> and
you want to match against the FQN, and <b>not</b> the simple name "MyOrder" then
do as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   .bean(OrderService.class, <span class="code-quote">"doSomething(com.foo.MyOrder)"</span>)
</pre>
</div></div>

<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td>Camel currently only
supports either specifying parameter binding or type per parameter in the method name option.
You <b>cannot</b> specify both at the same time, such as 
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
doSomething(com.foo.MyOrder ${body}, <span class="code-object">boolean</span>
${header.high})
</pre>
</div></div>
<p>This may change in the future.</p></td></tr></table></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CAMEL/Bean+Binding">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=63026&revisedVersion=39&originalVersion=38">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CAMEL/Bean+Binding?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message