{"id":2208,"date":"2012-02-07T13:28:52","date_gmt":"2012-02-07T11:28:52","guid":{"rendered":"https:\/\/test.viaboxx.de\/2012\/02\/07\/strongly-typed-camel-beanbindings\/"},"modified":"2021-08-11T09:47:15","modified_gmt":"2021-08-11T09:47:15","slug":"strongly-typed-camel-beanbindings","status":"publish","type":"post","link":"https:\/\/www.viaboxx.de\/en\/blog\/strongly-typed-camel-beanbindings\/","title":{"rendered":"Strongly Typed Camel BeanBindings"},"content":{"rendered":"\n<p>The&nbsp;<a style=\"color: #c20b1d;\" href=\"http:\/\/camel.apache.org\/\">Apache Camel&nbsp;<\/a>framework offers powerful mechanisms to determine which method of your beans to invoke. These are described here in the Camel documentation:&nbsp;<a style=\"color: #c20b1d;\" href=\"http:\/\/camel.apache.org\/bean-binding.html\">http:\/\/camel.apache.org\/bean-binding.html<\/a>.<\/p>\n\n\n\n<p>In practice, you have your beans defined with spring and declare their invocation in the Camel route definition either with \u201ebeanRef\u201c:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]\n.beanRef(\"orderService\", \"doSomething\")\n[\/codesyntax]<\/pre>\n\n\n\n<p>or with \u201eto\u201c:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]\n.to(\"bean:orderService?method=doSomething\")\n[\/codesyntax]<\/pre>\n\n\n\n<p>This has some disadvantages, for which we want to suggest a utility classes as a solution:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Your IDE cannot find the usages of the method invocation of method \u201edoSomething\u201c<\/li><li>Your IDE cannot assist you during refactorings, e.g. when renaming the method or changing the signature<\/li><li>Neither your IDE nor the compiler can complain about typos in method names. You will find typos during runtime, not during compile-time.<\/li><\/ul>\n\n\n\n<p>Replacing the calls with process() is no solution, because you still want the Camel-comfort of the powerful bean-binding.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Using class BeanRef<\/strong><\/p>\n\n\n\n<p>To use strongly typed invocations in your camel route definitions, that avoid the disadvantages, you can use the utility class BeanRef, with a little more verbose syntax:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]\/\/ ...\nfrom(\"activemq:orders\").to(doSomething()).to(\"file:confirm.txt\")\n\/\/ ...\nprivate String doSomething() {\nreturn new BeanRef&amp;lt;OrderService&amp;gt;(OrderService.class) {\nprotected void call() {\nbean.doSomething(null);\n}\n}.uri();\n}\n[\/codesyntax]<\/pre>\n\n\n\n<p>This results in a single URI:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]from(\"activemq:orders\").to(\"bean:orderService?method=doSomething\").to(\"file:confirm.txt\")\n[\/codesyntax]<\/pre>\n\n\n\n<p>It does not matter, which parameter values you are using to invoke \u201edoSomething\u201c, but you need to pass the parameters of the required time, so that the compiler is satisfied. The real method of your bean will not be invoked with this parameter!<\/p>\n\n\n\n<p>When your route calls more&nbsp;myOrderBookService&nbsp;than one method on the service bean, you can call the methods inside call() in their adequate sequence:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]from(\"activemq:orders\").to(new BeanRef&amp;lt;OrderService&amp;gt;(OrderService.class) {\nprotected void call() {\nbean.validate(bean.parse(null));\nbean.doSomething(null);\n}\n}.uris()).to(\u201efile:confirm.txt\u201c)\n[\/codesyntax]<\/pre>\n\n\n\n<p>This results in an array of URIs:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]from(\"activemq:orders\").to(\n\"bean:orderService?method=parse\",\n\"bean:orderService?method=validate\",\n\"bean:orderService?method=doSomething\").to(\"file:confirm.txt\")\n[\/codesyntax]<\/pre>\n\n\n\n<p>When your service bean has a non-standard bean-name, you can use the second constructor of BeanRef to tell the bean-name you are using:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]private String doSomething() {\nreturn new BeanRef&amp;lt;SmartWebService&amp;gt;(\nSmartWebService.class, \"myOrderBookService\"){\nprotected void call() {\nbean.doSomething (null);\n}\n}.uri();\n}\n[\/codesyntax]<\/pre>\n\n\n\n<p>This produces the URI:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]\"bean:myOrderBookService?method=doSomething\"\n[\/codesyntax]<\/pre>\n\n\n\n<p class=\"has-medium-font-size\"><strong>How does it work?<\/strong><\/p>\n\n\n\n<p>During definition of the camel route, the call() method of the BeanRef-instance will be invoked with a proxy, that implements the interface of your service bean. The proxy just collects the method invocations and the uri()\/uris() methods return the URI-strings of all method invocations.<\/p>\n\n\n\n<p>This is he whole source of class BeanRef:<br><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[codesyntax lang=\"java\"]package de.viaboxx.camel;\n\nimport java.lang.reflect.*;\nimport java.util.*;\n\npublic abstract class BeanRef {\nprivate final Class beanType;\nprivate final String beanName;\nprotected T bean;\n\npublic BeanRef(Class beanType) {\nthis.beanType = beanType;\nthis.beanName = uncapitalize(beanType.getSimpleName());\n}\n\npublic BeanRef(Class beanType, String beanName) {\nthis.beanType = beanType;\nthis.beanName = beanName;\n}\n\npublic static String uncapitalize(String str) {\nint strLen;\nif (str == null || (strLen = str.length()) == 0) {\nreturn str;\n}\nint i = 0;\nwhile (i &amp;lt; str.length() &amp;amp;&amp;amp; Character.isUpperCase(str.charAt(i))) {\ni++;\n}\nif (i == 0) {\nreturn str;\n} else {\nif (i &amp;gt; 1) i--;\nreturn new StringBuilder(strLen)\n.append(str.substring(0, i).toLowerCase())\n.append(str.substring(i))\n.toString();\n}\n}\n\nprotected abstract void call() throws Throwable;\n\npublic String[] uris() {\nCollector collector = evaluate();\nreturn toUris(collector);\n}\n\nprivate String[] toUris(Collector collector) {\nString[] uris = new String[collector.calls.size()];\nfor (int i = 0; i &amp;lt; collector.calls.size(); i++) {\nuris[i] = toUri(collector, i);\n}\nreturn uris;\n}\n\npublic String uri() {\nCollector collector = evaluate();\nif (collector.calls.size() != 1) {\nthrow new RuntimeException(\n\"uri() requires a single call, use uris() instead for \" + Arrays.toString(toUris(collector)));\n}\nreturn toUri(collector, 0);\n}\n\npublic String method() {\nCollector collector = evaluate();\nif (collector.calls.size() != 1) {\nthrow new RuntimeException(\n\"method() requires a single call, at \" + Arrays.toString(toUris(collector)));\n}\nreturn collector.calls.get(0);\n}\n\npublic String[] methods() {\nCollector collector = evaluate();\nreturn collector.calls.toArray(new String[collector.calls.size()]);\n}\n\nprivate Collector evaluate() {\nCollector collector = new Collector();\n\/\/noinspection unchecked\nbean = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),\nnew Class[]{beanType},\ncollector);\ntry {\ncall();\n} catch (Throwable throwable) {\nthrow new RuntimeException(\"Unexpected exception during configuration\", throwable);\n}\nbean = null;\nreturn collector;\n}\n\npublic String getBeanName() {\nreturn beanName;\n}\n\nprivate String toUri(Collector collector, int i) {\nreturn \"bean:\" + getBeanName() + \"?method=\" + collector.calls.get(i);\n}\n\nprivate static class Collector implements InvocationHandler {\nList calls = new LinkedList();\n\npublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {\ncalls.add(method.getName());\nreturn null;\n}\n}\n\n}\n[\/codesyntax]<\/pre>\n\n\n\n<p>If you are using Groovy instead of Java, you can easily think of a variant of BeanRef using Closures, that avoid most of the syntax overhead of Java, if you want to invoke your beans that way.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The&nbsp;Apache Camel&nbsp;framework offers powerful mechanisms to determine which method of your beans to invoke. These are described here in the Camel documentation:&nbsp;http:\/\/camel.apache.org\/bean-binding.html. In practice, you have [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","site-sidebar-layout":"default","site-content-layout":"default","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"default","adv-header-id-meta":"","stick-header-meta":"default","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[76],"tags":[],"class_list":["post-2208","post","type-post","status-publish","format-standard","hentry","category-code"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"Simon Tiffert","author_link":"https:\/\/www.viaboxx.de\/en\/blog\/author\/simon-tiffertviaboxx-de\/"},"uagb_comment_info":0,"uagb_excerpt":"The&nbsp;Apache Camel&nbsp;framework offers powerful mechanisms to determine which method of your beans to invoke. These are described here in the Camel documentation:&nbsp;http:\/\/camel.apache.org\/bean-binding.html. In practice, you have [&hellip;]","_links":{"self":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts\/2208"}],"collection":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/comments?post=2208"}],"version-history":[{"count":2,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts\/2208\/revisions"}],"predecessor-version":[{"id":7052,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/posts\/2208\/revisions\/7052"}],"wp:attachment":[{"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/media?parent=2208"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/categories?post=2208"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.viaboxx.de\/en\/wp-json\/wp\/v2\/tags?post=2208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}