Sunday, October 30, 2011

jDTO Binder - Java DTO Framework

DTO design pattern is mainly used to make a clean separation between layers. The DTO objects are meant to be part of the API of each application layer. Even though they're quite good on separation, they do have some costs associated: If not well managed, you'd probably end up by having lots of them, sometimes with mostly the same attributes between one another; on the other hand you might mitigate this by making a huge DTO with lots of information but ending up with the loss of lazy loading from the persistence layer. The previous costs must be managed by the developer and there's not much a framework can do besides generating the DTO classes, which have it's own disadvantages.

One really painful thing about using the DTO pattern is that the developer must take care of copying the data from one side to another and that's where jDTO Binder framework comes in handy. This framework is also an implementation of a bigger concept which I like to call "Object to Object Mapping" or simply OOM, and this concept is vey similar to another related and existing concepts like Object Relational Mapping (ORM) and Object XML Mapping (OXM).

This framework is still under development, but is quite stable to be used in production environments, in fact it is being used successfully on production environments.

The url for the full documentation can be found here:
https://github.com/juancavallotti/jDTO-Binder/wiki/jDTO-Binder---Java-DTO-framework.

And here's how to get started:

An example project can be found for download here.

First of all, we need to add the dependencies to our pom.xml file:

<dependency>
    <groupId>com.juancavallotti</groupId>
    <artifactId>jdto</artifactId>
    <version>0.4</version>
</dependency>
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.2</version>
</dependency>

I've decided the framework shouldn't have too many dependencies, so I've picked up those which must be (IMHO) in every serious java project:

  • SLF4J - So you can log the output with your favorite logger.
  • Commons Lang - This library is really useful, so if you're not using it, you should!

And also the repository to get jDTO:

    <repositories>
        <repository>
            <id>com. juancavallotti</id> 
            <name>jdto</name> 
            <url>http://juancavallotti.com/maven2</url> 
            <layout>default</layout>
        </repository>    
    </repositories>

Next we need to create some classes to act as source business objects, note that jDTO uses the property accessor methods (AKA getters and setters) to read property values from source beans, you should consider this and you can take advantage of this fact because you can read information without necessarily accessing a field.

A typical person class:

public class Person  implements Serializable {
    private long id;
    private String firstName;
    private String lastName;
    private Date birthDay;
    //GETTERS AND SETTERS
}

And a bill class with it's items:

public class Bill {
    private String clientName;
    private Date billExpiration;
    private List<BillItem> items;
    //GETTERS AND SETTERS
}

public class BillItem {
    private String itemName;
    private double price;
    private int amount;
    private double taxPercentage;
    //GETTERS AND SETTERS
}

These classes are used to show some of the features of the framework.

So we're now ready to start filling out some DTO's.

First we'll take a look a the PersonDTO, this one is rather simple, but it shows some of the key features of jDTO framework, binding by convention (default behavior), formatting fields and composing one field out of multiple fields:

public class PersonDTO implements Serializable {
    
    //bound by convention
    private long id;
    
    @Source(value="birthDay", merger=DateFormatMerger.class, 
            mergerParam="dd/MM/yyyy")
    private String birthday;
    
    @Sources(value={@Source("firstName"), @Source("lastName")}, 
            merger=StringFormatMerger.class, mergerParam="%s %s")
    private String fullName;
    //GETTERS AND SETTERS
}

And finally, we use the framework to bind the data:

DTOBinder binder = DTOBinderFactory.getBinder();

//bind a person to a person DTO
Person person = SampleData.samplePerson();
PersonDTO dto = binder.bindFromBusinessObject(PersonDTO.class, person);

It's really recommended you keep the DTOBinder instance as a singleton, so for that matter, the framework already provides you this facility, you  only need to call DTOBinderFactory.getBinder() and it's all done for you.

Next, we may want to build a DTO out of a bill but this time we just want the customer name and the amount of money the bill is worth, so here is how the DTO looks like:
public class BillDTO {
    
    //bound by convention
    private String clientName;
        
    @Source(value="items", merger=SumExpressionMerger.class, 
            mergerParam="(price * amount) * (1 + taxPercentage*0.01)")
    private double billTotalPrice;
    //GETTERS AND SETTERS
}

The final application code looks like:

public static void main(String[] args) {
        
    //get an instance of a singleton binder
    DTOBinder binder = DTOBinderFactory.getBinder();
    
    //bind a person to a person DTO
    Person person = SampleData.samplePerson();
    PersonDTO dto = binder.bindFromBusinessObject(PersonDTO.class, person);
    
    System.out.println(dto);
        
    
    Bill bill = SampleData.sampleBill();
    BillDTO billdto = binder.bindFromBusinessObject(BillDTO.class, bill);
    
    System.out.println(billdto);
}

And the output is:
PersonDTO{id=1, birthday=30/10/1982, fullName=Michael Princeton}
BillDTO{clientName=I'm a Client, billTotalPrice=22.0}

This is all for this small tutorial, please feel free to submit bug reports or feature requests on the issue tracker of the github project.

No comments:

Post a Comment