camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Camel > Dozer Type Conversion
Date Thu, 23 Feb 2012 07:06: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/Dozer+Type+Conversion">Dozer
Type Conversion</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~davsclaus">Claus
Ibsen</a>
    </h4>
        <br/>
                         <h4>Changes (4)</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" >h2. Support for Dozer in Camel <br>
<br></td></tr>
            <tr><td class="diff-changed-lines" >Camel provides a simple mechanism
to integrate Dozer Mappers with it&#39;s own powerful [Type Conversion|http://camel.apache.org/type-converter.html]
framework. Its configured by creating an instance of <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">&#39;DozerTypeConverterLoader&#39;</span>
<span class="diff-added-words"style="background-color: #dfd;">{{DozerTypeConverterLoader}}</span>
providing it the camel context and an optional Dozer mapper. If no mapper is supplied, <span
class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> Camel&#39;s registry will be searched for suitable instances. The loader
will query the Dozer Mapper for the the types it converts and a register them with Camel&#39;s
<span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">Conversionn</span>
<span class="diff-added-words"style="background-color: #dfd;">type conversion</span>
framework to be handled by the mapper. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{info:title=Limitation}
<br>The Camel Dozer type converter does not support having the same type conversion
paris in different mapping ids (eg map-id) in Dozer. <br>{info} <br> <br>
<br></td></tr>
            <tr><td class="diff-unchanged" >In Java it can be configured as follows:
<br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{code: lang=xml} <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >&lt;!-- the registry will
be <span class="diff-changed-words">scann<span class="diff-added-chars"style="background-color:
#dfd;">e</span>d</span> and &#39;mapper&#39; below will be found and
installed --&gt; <br></td></tr>
            <tr><td class="diff-changed-lines" >&lt;bean id=&quot;dozerConverterLoader&quot;
<span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> class=&quot;org.apache.camel.converter.dozer.DozerTypeConverterLoader&quot;
/&gt; <br></td></tr>
            <tr><td class="diff-unchanged" > <br>&lt;bean id=&quot;mapper&quot;
class=&quot;org.dozer.DozerBeanMapper&quot;&gt; <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="DozerTypeConversion-DozerTypeConversion."></a>Dozer
Type Conversion.</h1>

<p><a href="http://dozer.sourceforge.net/documentation/about.html" class="external-link"
rel="nofollow">Dozer</a> is a fast and flexible framework for mapping back and forth
between Java Beans. Coupled with Camel's automatic type conversion, it's a formidable tool
for dealing object to object mapping headaches that crop up in enterprise integration projects.
</p>

<p>To explain how Dozer can be uses within Camel we'll use the following example of
a simple Customer Support Service. The initial version of the Service defined a 'Customer'
object used with a very flat structure. </p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Legacy Customer Service Class</b></div><div
class="codeContent panelContent">
<pre class="code-java">

<span class="code-keyword">public</span> class Customer {
    <span class="code-keyword">private</span> <span class="code-object">String</span>
firstName;
    <span class="code-keyword">private</span> <span class="code-object">String</span>
lastName;
    <span class="code-keyword">private</span> <span class="code-object">String</span>
street;
    <span class="code-keyword">private</span> <span class="code-object">String</span>
zip;

    <span class="code-keyword">public</span> Customer() {}

    <span class="code-keyword">public</span> Customer(<span class="code-object">String</span>
firstName, <span class="code-object">String</span> lastName, <span class="code-object">String</span>
zip, <span class="code-object">String</span> street) {
        <span class="code-keyword">this</span>.firstName = firstName;
        <span class="code-keyword">this</span>.lastName = lastName;
        <span class="code-keyword">this</span>.zip = zip;
        <span class="code-keyword">this</span>.street = street;
    }

    <span class="code-keyword">public</span> <span class="code-object">String</span>
getFirstName() {
        <span class="code-keyword">return</span> firstName;
    }

    <span class="code-keyword">public</span> void setFirstName(<span class="code-object">String</span>
firstName) {
        <span class="code-keyword">this</span>.firstName = firstName;
    }

    ... getters and setters <span class="code-keyword">for</span> each field
</pre>
</div></div>

<p>In the next version it was decided to structure the data better in the model by moving
the address data into its own type, with the resultin domain object ending up looking like</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Next Gen Customer object</b></div><div
class="codeContent panelContent">
<pre class="code-java">

<span class="code-keyword">public</span> class Customer {
    <span class="code-keyword">private</span> <span class="code-object">String</span>
firstName;
    <span class="code-keyword">private</span> <span class="code-object">String</span>
lastName;
    <span class="code-keyword">private</span> Address address;

    <span class="code-keyword">public</span> Customer() {}

    <span class="code-keyword">public</span> Customer(<span class="code-object">String</span>
firstName, <span class="code-object">String</span> lastName, Address address)
{
        <span class="code-keyword">this</span>.firstName = firstName;
        <span class="code-keyword">this</span>.lastName = lastName;
        <span class="code-keyword">this</span>.address = address;
    }
    ....


<span class="code-keyword">public</span> class Address {
    <span class="code-keyword">private</span> <span class="code-object">String</span>
zipCode;
    <span class="code-keyword">private</span> <span class="code-object">String</span>
streetName;

    <span class="code-keyword">public</span> Address() {}

    <span class="code-keyword">public</span> Address(<span class="code-object">String</span>
zipCode, <span class="code-object">String</span> streetName) {
        <span class="code-keyword">this</span>.zipCode = zipCode;
        <span class="code-keyword">this</span>.streetName = streetName;
    }
</pre>
</div></div> 

<p>Much nicer! But as often occurs, the previous version of the service, with the old
flat 'Customer' object, was in production with a client and the project must support the legacy
interface. To support both versions, we must add a mechanism to convert between the old Customer
service type and the new Customer domain type and back again. It would be a simple matter
to write a custom converter class to map between them, but this may not be the only service/domain
inconsistency and these tedious and error prone custom mappings could quickly start to add
up, and bugs with them.</p>

<p>To a large extent the two object share identical structure, with only the address
representation being different. It would be very helpful if there were a practical way to
to automate this kind of mapping, such that the similar properties could get mapped automatically
and only the inconsistencies requiring custom mapping.</p>

<p>This is where Dozer comes in; It uses reflection to map data between two bean types
using a set of simple mapping rules. Where no rule is specified, dozer will attempt to map
between them by using matching properties of two beans. In this way focus can be given to
the inconsistencies between the beans i.e. the address properties, knowing that dozer will
automatically match and convert the others.</p>

<h2><a name="DozerTypeConversion-ConfiguringDozer"></a>Configuring Dozer</h2>

<p>Dozer's configuration is extremely flexible and many mapping scenarios are covered
<a href="http://dozer.sourceforge.net/documentation/mappings.html" class="external-link"
rel="nofollow">here</a>. For our simple example, the configuration looks like the
following.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
&lt;mappings xmlns=<span class="code-quote">"http://dozer.sourceforge.net"</span>
<span class="code-keyword">xmlns:xsi</span>=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span>
  xsi:schemaLocation=<span class="code-quote">"http://dozer.sourceforge.net  http://dozer.sourceforge.net/schema/beanmapping.xsd"</span>&gt;
  <span class="code-tag">&lt;mapping&gt;</span>
    <span class="code-tag">&lt;class-a&gt;</span>org.apache.camel.converter.dozer.service.Customer<span
class="code-tag">&lt;/class-a&gt;</span>
    <span class="code-tag">&lt;class-b&gt;</span>org.apache.camel.converter.dozer.model.Customer<span
class="code-tag">&lt;/class-b&gt;</span>
    <span class="code-tag">&lt;field&gt;</span>
      <span class="code-tag">&lt;a&gt;</span>street<span class="code-tag">&lt;/a&gt;</span>
      <span class="code-tag">&lt;b&gt;</span>address.streetName<span
class="code-tag">&lt;/b&gt;</span>
    <span class="code-tag">&lt;/field&gt;</span>
    <span class="code-tag">&lt;field&gt;</span>
      <span class="code-tag">&lt;a&gt;</span>zip<span class="code-tag">&lt;/a&gt;</span>
      <span class="code-tag">&lt;b&gt;</span>address.zipCode<span class="code-tag">&lt;/b&gt;</span>
    <span class="code-tag">&lt;/field&gt;</span>
  <span class="code-tag">&lt;/mapping&gt;</span>
<span class="code-tag">&lt;/mappings&gt;</span>
</pre>
</div></div>

<h2><a name="DozerTypeConversion-SupportforDozerinCamel"></a>Support for
Dozer in Camel</h2>

<p>Camel provides a simple mechanism to integrate Dozer Mappers with it's own powerful
<a href="http://camel.apache.org/type-converter.html" class="external-link" rel="nofollow">Type
Conversion</a> framework. Its configured by creating an instance of <tt>DozerTypeConverterLoader</tt>
providing it the camel context and an optional Dozer mapper. If no mapper is supplied, Camel's
registry will be searched for suitable instances. The loader will query the Dozer Mapper for
the the types it converts and a register them with Camel's type conversion framework to be
handled by the mapper.</p>

<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><b>Limitation</b><br
/>The Camel Dozer type converter does not support having the same type conversion paris
in different mapping ids (eg map-id) in Dozer.</td></tr></table></div>


<p>In Java it can be configured as follows:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
DozerBeanMapper mapper = <span class="code-keyword">new</span> DozerBeanMapper(Arrays.asList(<span
class="code-keyword">new</span> <span class="code-object">String</span>[]{<span
class="code-quote">"mapping.xml"</span>}));
<span class="code-keyword">new</span> DozerTypeConverterLoader(camelContext, mapper);
</pre>
</div></div>

<p>Or in Spring</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">

<span class="code-tag"><span class="code-comment">&lt;!-- the registry will
be scanned and 'mapper' below will be found and installed --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"dozerConverterLoader"</span>
class=<span class="code-quote">"org.apache.camel.converter.dozer.DozerTypeConverterLoader"</span>
/&gt;</span>
  
<span class="code-tag">&lt;bean id=<span class="code-quote">"mapper"</span>
class=<span class="code-quote">"org.dozer.DozerBeanMapper"</span>&gt;</span>
  <span class="code-tag">&lt;property name=<span class="code-quote">"mappingFiles"</span>&gt;</span>
    <span class="code-tag">&lt;list&gt;</span>
      <span class="code-tag">&lt;value&gt;</span>mapping.xml<span class="code-tag">&lt;/value&gt;</span>
    <span class="code-tag">&lt;/list&gt;</span>
  <span class="code-tag">&lt;/property&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>

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

<p>Now, where necessary, Camel will use Dozer to do conversions; In our case between
the new domain and legacy Customer types e.g. </p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">// given the following route
</span>from(<span class="code-quote">"direct:legacy-service-in"</span>).bean(<span
class="code-keyword">new</span> CustomerProcessor());

<span class="code-comment">// and a processor
</span>
<span class="code-keyword">public</span> class CustomerProcessor {

    <span class="code-keyword">public</span> Customer processCustomer(org.apache.camel.converter.dozer.model.Customer
customer) {
       ...
    }
}

<span class="code-comment">// service objects can be sent to the processor and automagically
converted by Camel &amp; Dozer
</span>template.sendBody(<span class="code-quote">"direct:legacy-service-in"</span>,<span
class="code-keyword">new</span> org.apache.camel.converter.dozer.service.Customer(<span
class="code-quote">"Bob"</span>, <span class="code-quote">"Roberts"</span>,
<span class="code-quote">"12345"</span>, <span class="code-quote">"1 Main
st."</span>));

</pre>
</div></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/Dozer+Type+Conversion">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=12321582&revisedVersion=2&originalVersion=1">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CAMEL/Dozer+Type+Conversion?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message