<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3029196619690502189</id><updated>2011-04-21T12:53:15.324-07:00</updated><category term='Hibernate'/><category term='Spring'/><category term='Java EE'/><category term='Java'/><category term='DTO'/><title type='text'>Java and whatnot</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://am-i-drunk.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3029196619690502189/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://am-i-drunk.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nille</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3029196619690502189.post-7341766936328057480</id><published>2009-03-08T05:28:00.000-07:00</published><updated>2009-05-02T10:12:57.701-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='DTO'/><category scheme='http://www.blogger.com/atom/ns#' term='Java EE'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Making Java EE less of a pain</title><content type='html'>Java EE has improved a lot since the days of EJB 2.1. It's still a pain though. I'd say that application servers are responsible for 75% or so of the pain - I don't like application servers, in case that's not clear - but the APIs and required patterns are not to be forgotten.&lt;br /&gt;&lt;br /&gt;Me and my colleague have spent a lot of time discussing/fighting about Java EE application architecture. One camp likes application servers and prefer passing domain objects to controllers and to the presentation. Another camp don't like application servers and prefer strict transactional boundaries through which no domain objects are permitted to leak. I don't like application servers and I think that the business domain should stay in the business layer (guess how I feel about JBoss Seam). A consequence of my position is that I inevitably must like DTOs over passing domain objects to controller/presentation layer. Well... not so much. It's a pain to compose DTOs and it makes programming boring.&lt;br /&gt;&lt;br /&gt;There are automated tools out there for generating DTOs from domain objects, but in my experience they solve the problem by introducing another problem, namely the need for XML configuration (why is XML always the solution?). So, I figured I'd start an open source project where different Java EE strategies can be tested and discussed. It's aptly named Bumblebee (it's freakin' hopeless to find an available name these days) and currently implements DTO assembly using annotations only.&lt;br /&gt;&lt;br /&gt;Ok, lets start with a simple example. Most business domains define the concept of a user. A user generally has some information associated with him/her, and for the sake of argument I'll separate these into two entities, like this:&lt;br /&gt;&lt;br /&gt;&lt;div id='iframeDiv66da5d8b-d5ef-4253-a016-7404ad6d4aa1' style='display:none;margin:0px;'&gt;&lt;iframe id='iframe66da5d8b-d5ef-4253-a016-7404ad6d4aa1' src='http://www.blogtrog.com/code.aspx?id=66da5d8b-d5ef-4253-a016-7404ad6d4aa1' style='width: 600px; height: 200px; border: 1px solid #e0e0e0;margin:0px;' frameborder='0'&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div id='noIframeDiv66da5d8b-d5ef-4253-a016-7404ad6d4aa1' style='display:block;margin:0px;'&gt;&lt;pre&gt;&lt;div&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style="color: #000000;"&gt;@Entity&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; User {&lt;br /&gt;   &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; Long getId() { ... }&lt;br /&gt;   &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; String getUsername() { ... }&lt;br /&gt;   &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; UserInfo getUserInfo() { ... }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Entity&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; UserInfo {&lt;br /&gt;   &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; String getFirstName() { ... }&lt;br /&gt;   &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; String getLastName() { ... }&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;script language='javascript' src='http://www.blogtrog.com/scripts/bt_code.js' type='text/javascript'&gt;&lt;/script&gt;&lt;script language='javascript' type='text/javascript'&gt;bt_code_init('66da5d8b-d5ef-4253-a016-7404ad6d4aa1');&lt;/script&gt;&lt;br /&gt;If we don't want the domain objects to be accessible from the presentation/controller/session layers, we'll need to define data transfer objects that transfer raw data out of the business layer. Let's say we want to encapsulate username, first name and last name in a DTO. Our resulting business method would typically look like this:&lt;br /&gt;&lt;br /&gt;&lt;div id="iframeDiv1a7492a5-19f3-4a88-b160-c402d7ebae8e" style="display:none;margin:0px;"&gt;&lt;iframe id="iframe1a7492a5-19f3-4a88-b160-c402d7ebae8e" src="http://www.blogtrog.com/code.aspx?id=1a7492a5-19f3-4a88-b160-c402d7ebae8e" style="width: 600px; height: 200px; border: 1px solid #e0e0e0;margin:0px;" frameborder="0"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div id="noIframeDiv1a7492a5-19f3-4a88-b160-c402d7ebae8e" style="display:block;margin:0px;"&gt;&lt;pre&gt;&lt;div&gt;&lt;!--  Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/  --&gt;&lt;span style="color:#000000;"&gt;@Stateless&lt;br /&gt;&lt;/span&gt;&lt;span style="color:#0000FF;"&gt;public&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000FF;"&gt;class&lt;/span&gt;&lt;span style="color:#000000;"&gt; UserServiceBean &lt;/span&gt;&lt;span style="color:#0000FF;"&gt;implements&lt;/span&gt;&lt;span style="color:#000000;"&gt; UserService {&lt;br /&gt; &lt;/span&gt;&lt;span style="color:#0000FF;"&gt;public&lt;/span&gt;&lt;span style="color:#000000;"&gt; UserDetails getUserDetails(String username) {&lt;br /&gt;    User user &lt;/span&gt;&lt;span style="color:#000000;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; userDAO.findByUsername(username);&lt;br /&gt;    UserDetails userDetails &lt;/span&gt;&lt;span style="color:#000000;"&gt;=&lt;/span&gt;&lt;span style="color:#000000;"&gt; &lt;/span&gt;&lt;span style="color:#0000FF;"&gt;new&lt;/span&gt;&lt;span style="color:#000000;"&gt; UserDetails();&lt;br /&gt;&lt;br /&gt;    userDetails.setUsername(user.getUsername());&lt;br /&gt;    userDetails.setFirstName(user.getUserInfo().getFirstName());&lt;br /&gt;    userDetails.setLastName(user.getUserInfo().getLastName());&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color:#0000FF;"&gt;return&lt;/span&gt;&lt;span style="color:#000000;"&gt; userDetails;&lt;br /&gt; }&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript"&gt;&lt;/script&gt;&lt;script language="javascript" type="text/javascript"&gt;bt_code_init('1a7492a5-19f3-4a88-b160-c402d7ebae8e');&lt;/script&gt;&lt;br /&gt;At some point, developers will become bored and write a converter/assembler for this, but the code is still there somewhere in the system. This is precisely the code I want to avoid, because it has nothing to do with the business logic, but is rather used to cope with technical limitations. So the goal in the Bumblebee DTO assembler is to provide automatic assembly of transfer objects while requireing as little information as possible from the developer.&lt;br /&gt;&lt;br /&gt;To define and assemble a DTO, you need to define a DataObject like such:&lt;br /&gt;&lt;br /&gt;&lt;div id='iframeDiv9e6a7345-ee09-458c-9b00-dcc43294bfe8' style='display:none;margin:0px;'&gt;&lt;iframe id='iframe9e6a7345-ee09-458c-9b00-dcc43294bfe8' src='http://www.blogtrog.com/code.aspx?id=9e6a7345-ee09-458c-9b00-dcc43294bfe8' style='width: 600px; height: 200px; border: 1px solid #e0e0e0;margin:0px;' frameborder='0'&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div id='noIframeDiv9e6a7345-ee09-458c-9b00-dcc43294bfe8' style='display:block;margin:0px;'&gt;&lt;pre&gt;&lt;div&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style="color: #000000;"&gt;@DataObject&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;interface&lt;/span&gt;&lt;span style="color: #000000;"&gt; UserDetails {&lt;br /&gt;&lt;br /&gt; @Value&lt;br /&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; String getUsername();&lt;br /&gt;&lt;br /&gt; @Value(&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;userDetails.firstName&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br /&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; String getFirstName();&lt;br /&gt;&lt;br /&gt; @Value(&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;userDetails.lastName&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br /&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; String getLastName();&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;script language='javascript' src='http://www.blogtrog.com/scripts/bt_code.js' type='text/javascript'&gt;&lt;/script&gt;&lt;script language='javascript' type='text/javascript'&gt;bt_code_init('9e6a7345-ee09-458c-9b00-dcc43294bfe8');&lt;/script&gt;&lt;br /&gt;When assembling our DTO in the business layer, we'll call upon Bumblebee to do the work:&lt;br /&gt;&lt;br /&gt;&lt;div id='iframeDivd8ef7d88-eeb2-49ef-b290-35d28ee08d5f' style='display:none;margin:0px;'&gt;&lt;iframe id='iframed8ef7d88-eeb2-49ef-b290-35d28ee08d5f' src='http://www.blogtrog.com/code.aspx?id=d8ef7d88-eeb2-49ef-b290-35d28ee08d5f' style='width: 600px; height: 200px; border: 1px solid #e0e0e0;margin:0px;' frameborder='0'&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div id='noIframeDivd8ef7d88-eeb2-49ef-b290-35d28ee08d5f' style='display:block;margin:0px;'&gt;&lt;pre&gt;&lt;div&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style="color: #0000FF;"&gt;import&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; com.googlecode.bumblebee.dto.Bumblebee.&lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&lt;br /&gt;@Stateless &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; (or @Service or whatever)&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; UserServiceBean &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;implements&lt;/span&gt;&lt;span style="color: #000000;"&gt; UserService {&lt;br /&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; UserDetails getUserDetails(String username) {&lt;br /&gt;    User user &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; userDAO.findByUsername(username);&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; assemble(UserDetails.&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;).from(user);&lt;br /&gt; }&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;script language='javascript' src='http://www.blogtrog.com/scripts/bt_code.js' type='text/javascript'&gt;&lt;/script&gt;&lt;script language='javascript' type='text/javascript'&gt;bt_code_init('d8ef7d88-eeb2-49ef-b290-35d28ee08d5f');&lt;/script&gt;&lt;br /&gt;...and that's it. The framework will generate a concrete implementation class that extracts the data from the domain object using the provided expressions in the @Value annotations (DTO EL, currently only supports property paths).&lt;br /&gt;&lt;br /&gt;That's my two cents. You'll find the project at &lt;a href="http://code.google.com/p/java-bumblebee/"&gt;http://code.google.com/p/java-bumblebee&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3029196619690502189-7341766936328057480?l=am-i-drunk.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://am-i-drunk.blogspot.com/feeds/7341766936328057480/comments/default' title='Kommentarer till inlägget'/><link rel='replies' type='text/html' href='http://am-i-drunk.blogspot.com/2009/03/making-java-ee-less-of-pain.html#comment-form' title='1 kommentarer'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3029196619690502189/posts/default/7341766936328057480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3029196619690502189/posts/default/7341766936328057480'/><link rel='alternate' type='text/html' href='http://am-i-drunk.blogspot.com/2009/03/making-java-ee-less-of-pain.html' title='Making Java EE less of a pain'/><author><name>Nille</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
