<?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-1798575258168757722</id><updated>2011-07-28T19:09:52.700-05:00</updated><category term='Hibernate'/><category term='FlexORM'/><category term='Flex'/><category term='Grails'/><category term='Spring'/><category term='BlazeDS'/><category term='AIR'/><category term='Redpoint'/><title type='text'>Redpoint Technologies (SPR inc)</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-5707691262598967324</id><published>2010-10-30T14:30:00.008-05:00</published><updated>2010-10-30T15:19:53.729-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Gorm Performance of collections - continued</title><content type='html'>In my last post - I told you about the issue Burt Beckwith brought up at the SpringOne conference with adding a member to a 1-to-many relationship.  That issue is that hibernate will load all of the values from the many side to make sure the new item can be added.  If this number is small, then that is fine - but if there are a lot then you have a potential issue.&lt;br /&gt;&lt;br /&gt;Burt also talked about a solution.  His suggested solution reminded me a little of the old joke:&lt;br /&gt;&lt;br /&gt;Patient: Doctor, Doctor - it hurts when I do this&lt;br /&gt;Doctor: Then don't do that&lt;br /&gt;&lt;br /&gt;Burt's suggestion was to not model Libary to Visits as a 1-to-many relationship.  Instead remove the collection altogether from the Library and give the Visit a reference back to the library.&lt;br /&gt;&lt;br /&gt;Now the Library and the Visit look like the following:&lt;br /&gt;Library:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:    &lt;br /&gt;2:  class Library {  &lt;br /&gt;3:   String name  &lt;br /&gt;4:     &lt;br /&gt;5:    static constraints = {  &lt;br /&gt;6:    }  &lt;br /&gt;7:  }  &lt;br /&gt;8:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Visit:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  class Visit {  &lt;br /&gt;2:   String personName  &lt;br /&gt;3:   Date visitDate = new Date()  &lt;br /&gt;4:    &lt;br /&gt;5:   Library library  &lt;br /&gt;6:    static constraints = {  &lt;br /&gt;7:    }  &lt;br /&gt;8:  }  &lt;br /&gt;9:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice now that Library has no reference at all to a Visit, but Visit still has a reference to the Library.&lt;br /&gt;&lt;br /&gt;Because of this change, it will change our usage of these domain classes - but interestingly enough it does not change the table definition.  Lets look at the tables for the original Library and the new Library:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  create table library (  &lt;br /&gt;2:       id bigint generated by default as identity (start with 1),   &lt;br /&gt;3:       version bigint not null,   &lt;br /&gt;4:       name varchar(255) not null,   &lt;br /&gt;5:       primary key (id));  &lt;br /&gt;6:  &lt;New Library Definition&gt;&lt;br /&gt;7:  create table library (  &lt;br /&gt;8:       id bigint generated by default as identity (start with 1),   &lt;br /&gt;9:       version bigint not null,   &lt;br /&gt;10:       name varchar(255) not null,   &lt;br /&gt;11:       primary key (id));  &lt;br /&gt;12:         &lt;br /&gt;13:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can see from above that the table definition is exactly the same so there will be no impact at the database level - but there is an impact at the code level.&lt;br /&gt;&lt;br /&gt;Now, instead of adding Visits to a library we have to pass a reference to the library to the Visit.  Something like the following:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:    Library library = new Library(name:'LocalLibrary3')  &lt;br /&gt;2:    int maxVisits = 100  &lt;br /&gt;3:    library.save()  &lt;br /&gt;4:    &lt;br /&gt;5:    (1..maxVisits).each {  &lt;br /&gt;6:     new Visit(personName:"person${it}", library:library).save()  &lt;br /&gt;7:    }  &lt;br /&gt;8:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice above we create an instance of the Library, then as we create Visits we add a reference to the library that the visit is associated with.  There is no dynamic method on the Library class called 'addToVisits' - because there are no visits.&lt;br /&gt;&lt;br /&gt;Lets look at the entire integration test.  Note that I changed the name of the Library class to Library3 and Visit3 so they did not conflict with the original classes.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:   void testAddingLibrary2Visits3() {  &lt;br /&gt;2:    Library3 library3 = new Library3(name:'LocalLibrary3')  &lt;br /&gt;3:    int maxVisits = 100  &lt;br /&gt;4:    library3.save()  &lt;br /&gt;5:    &lt;br /&gt;6:    (1..maxVisits).each {  &lt;br /&gt;7:     new Visit3(personName:"person${it}", library:library3).save()  &lt;br /&gt;8:    }  &lt;br /&gt;9:    &lt;br /&gt;10:    sessionFactory.getCurrentSession().flush()  &lt;br /&gt;11:    sessionFactory.getCurrentSession().clear()  &lt;br /&gt;12:    &lt;br /&gt;13:    assertEquals 1, Library3.count()  &lt;br /&gt;14:    assertEquals maxVisits, Visit3.count()  &lt;br /&gt;15:    &lt;br /&gt;16:    sessionFactory.getCurrentSession().flush()  &lt;br /&gt;17:    sessionFactory.getCurrentSession().clear()  &lt;br /&gt;18:    &lt;br /&gt;19:    println "============= Find the library ============="  &lt;br /&gt;20:    &lt;br /&gt;21:    Library3 library33 = Library3.findById(library3.id)  &lt;br /&gt;22:    &lt;br /&gt;23:    println "============= adding one more visit ============="  &lt;br /&gt;24:    Visit3 oneMoreVisit = new Visit3(personName:"oneMorePerson",library:library33)  &lt;br /&gt;25:    oneMoreVisit.save()  &lt;br /&gt;26:    println "============= saved new Visit one more visit ============="  &lt;br /&gt;27:    assertEquals maxVisits+1, Visit3.countByLibrary(library33)  &lt;br /&gt;28:    &lt;br /&gt;29:    sessionFactory.getCurrentSession().flush()  &lt;br /&gt;30:    sessionFactory.getCurrentSession().clear()  &lt;br /&gt;31:    println "============= Done adding one more visit ============="  &lt;br /&gt;32:    &lt;br /&gt;33:    println "============= Check count of libraries and visits ============="  &lt;br /&gt;34:    assertEquals 1, Library3.count()  &lt;br /&gt;35:    assertEquals maxVisits+1, Visit3.count()  &lt;br /&gt;36:   }  &lt;br /&gt;37:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lets look at each section of the unit test and the result sql statements:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  INTEGRATIONTEST  &lt;br /&gt;2:  println "============= Find the library ============="  &lt;br /&gt;3:  Library3 library33 = Library3.findById(library3.id)  &lt;br /&gt;4:    &lt;br /&gt;5:  SQL  &lt;br /&gt;6:  ============= Find the library =============  &lt;br /&gt;7:  Hibernate:   &lt;br /&gt;8:    select  &lt;br /&gt;9:      this_.id as id9_0_,  &lt;br /&gt;10:      this_.version as version9_0_,  &lt;br /&gt;11:      this_.name as name9_0_   &lt;br /&gt;12:    from  &lt;br /&gt;13:      library3 this_   &lt;br /&gt;14:    where  &lt;br /&gt;15:      this_.id=?  &lt;br /&gt;16:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;On line 3 above, we perform a find for the library instance. You can see this results in a single select, very much like the last time.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  INTEGRATION TEST  &lt;br /&gt;2:  println "============= adding one more visit ============="  &lt;br /&gt;3:  Visit3 oneMoreVisit = new Visit3(personName:"oneMorePerson",library:library33)  &lt;br /&gt;4:  oneMoreVisit.save()  &lt;br /&gt;5:    &lt;br /&gt;6:  SQL  &lt;br /&gt;7:  ============= adding one more visit =============  &lt;br /&gt;8:  Hibernate:   &lt;br /&gt;9:    insert   &lt;br /&gt;10:    into  &lt;br /&gt;11:      visit3  &lt;br /&gt;12:      (id, version, library_id, person_name, visit_date)   &lt;br /&gt;13:    values  &lt;br /&gt;14:      (null, ?, ?, ?, ?)  &lt;br /&gt;15:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This is where we really see the benefit.  On lines 3, we create the new Visit and pass a reference to the library.  On line 4, we save the new visit.  Notice the resulting sql does not make a select of all of the visits.  Instead it can insert the record directly into the table.  This clearly can be a huge performance gain if your collections are very large. &lt;br /&gt;&lt;br /&gt;This is something you need to think about when designing your model.  GORM can sometimes appear to be magic.  I was told once that if it appears to be magic it is because you do not understand it.  If you dont understand it, then subtle cases like this will cause you problems on a project.&lt;br /&gt;&lt;br /&gt;If you know about this ahead of time, then you can implement it the correct way.  But sometimes, it is not clear if you have to do this and you never want to make premature optimizations before you know you have to.  &lt;br /&gt;&lt;br /&gt;I was wondering then, what would happen if you implemented the collection in the conventional way - and then later had to change it.  The usage is significantly different that it would have a ripple effect in you code.  I wanted to see if I could retrofit the existing api, with the above implementation.&lt;br /&gt;&lt;br /&gt;I got close - but I could not get it to match completely.  I got very close, but I needed to add an additional flush:true in the original integration test.&lt;br /&gt;&lt;br /&gt;Below I show my attempt to modify the Library class to accommodate the above usage.  I called the new classes Library2 and Visit2.&lt;br /&gt;&lt;br /&gt;Library2&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  class Library2 {  &lt;br /&gt;2:    &lt;br /&gt;3:   String name  &lt;br /&gt;4:   Boolean visitsDirty = false  &lt;br /&gt;5:    &lt;br /&gt;6:   private List&amp;lt;Visit2&amp;gt; _visits = new ArrayList&amp;lt;Visit2&amp;gt;()  &lt;br /&gt;7:    &lt;br /&gt;8:   Library2 addToVisits(Visit2 theVisit) {  &lt;br /&gt;9:    if (theVisit) {  &lt;br /&gt;10:     theVisit.library = this  &lt;br /&gt;11:     _visits &amp;lt;&amp;lt; theVisit  &lt;br /&gt;12:     visitsDirty = true  &lt;br /&gt;13:    }  &lt;br /&gt;14:    return this  &lt;br /&gt;15:   }  &lt;br /&gt;16:    &lt;br /&gt;17:   List&amp;lt;Visit2&amp;gt; getVisits() {  &lt;br /&gt;18:    List&amp;lt;Visit2&amp;gt; theVisits = Visit2.findAllByLibrary(this)  &lt;br /&gt;19:   }  &lt;br /&gt;20:    &lt;br /&gt;21:   def afterSave = {  &lt;br /&gt;22:    Library2 lib2 = Library2.load(this.id)  &lt;br /&gt;23:    _visits.each {  &lt;br /&gt;24:     it.library = lib2  &lt;br /&gt;25:     it.save()  &lt;br /&gt;26:    }  &lt;br /&gt;27:    _visits.clear()  &lt;br /&gt;28:    visitsDirty = false  &lt;br /&gt;29:   }  &lt;br /&gt;30:   def afterInsert = {  &lt;br /&gt;31:    Library2 lib2 = Library2.load(this.id)  &lt;br /&gt;32:    _visits.each {  &lt;br /&gt;33:     it.library = lib2  &lt;br /&gt;34:     it.save()  &lt;br /&gt;35:    }  &lt;br /&gt;36:    _visits.clear()  &lt;br /&gt;37:    visitsDirty = false  &lt;br /&gt;38:   }  &lt;br /&gt;39:   def afterUpdate = {  &lt;br /&gt;40:    Library2 lib2 = Library2.load(this.id)  &lt;br /&gt;41:    _visits.each {  &lt;br /&gt;42:     it.library = lib2  &lt;br /&gt;43:     it.save()  &lt;br /&gt;44:    }  &lt;br /&gt;45:    _visits.clear()  &lt;br /&gt;46:    visitsDirty = false  &lt;br /&gt;47:   }  &lt;br /&gt;48:   def beforeDelete = {  &lt;br /&gt;49:    Visit.executeUpdate("delete Visit2 v where v.library = ?", [this])  &lt;br /&gt;50:   }  &lt;br /&gt;51:    &lt;br /&gt;52:   static constraints = {  &lt;br /&gt;53:   }  &lt;br /&gt;54:  }  &lt;br /&gt;55:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;as you can see I had to hook into a number of Hibernate events.  &lt;br /&gt;&lt;br /&gt;My conclusion after the exercise above was that it was better to re-write the implementation than it was to try to retrofit the api.&lt;br /&gt;&lt;br /&gt;I hope you found this useful and will be better prepared to design and implement your collections with Grails and GORM.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-5707691262598967324?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/5707691262598967324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=5707691262598967324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/5707691262598967324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/5707691262598967324'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/10/gorm-performance-of-collections.html' title='Gorm Performance of collections - continued'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-8316467226332944169</id><published>2010-10-22T18:00:00.010-05:00</published><updated>2010-10-22T19:25:46.070-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>SpringOne 2GX Conf - GORM Performance</title><content type='html'>I was lucky enough to attend the SpringOne 2GX conference held in the Chicago area this week.  There were plenty of great sessions - and they have given me much information to blog about. &lt;br /&gt;&lt;br /&gt;This blog post is inspired by a session by Burt Beckwith who has an &lt;a href="http://burtbeckwith.com/blog/"&gt;awesome blog&lt;/a&gt; himself.  Check it out!&lt;br /&gt;&lt;br /&gt;Burt's session was called 'Advanced GORM - Performance, Customization and Monitoring'.  In this session he showed an interesting 'gotcha' which I looked into further and thought others might like to be made aware of this one.  I would like to say I knew this at some point - but I have to admit I had forgotten this potential issue.&lt;br /&gt;&lt;br /&gt;Two caveats:&lt;br /&gt;1) This issue is really a result of what hibernate has to do to make the domain model correct.  It is just that GORM makes it easy to fall into this issue - it is &lt;span style="font-weight:bold;"&gt;not&lt;/span&gt; a GORM issue.  It is also not really a hibernate issue either - it just is.&lt;br /&gt;2) Burt stressed that what he showed was to inform, not to bias people away from a particular modeling style. &lt;br /&gt;&lt;br /&gt;The issue is centered around Grails 'One-to-Many' relationships.  Burt used Library and Visit domain objects in his example - and if it is not too egregious - I will use the same in this blog post.&lt;br /&gt;&lt;br /&gt;Imagine we have to keep track of the number of visits to a particular library.  The standard modeling technique would be a single Library has many Visits.  This is very easy to model in GORM ( and that ease in a way contributes to the issue ).&lt;br /&gt;&lt;br /&gt;This can be modeled like the the following:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  class Library {  &lt;br /&gt;2:   String name  &lt;br /&gt;3:   static hasMany = [visits:Visit]  &lt;br /&gt;4:    &lt;br /&gt;5:  }  &lt;br /&gt;6:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Where a Visit might look like the following:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  class Visit {  &lt;br /&gt;2:   String personName  &lt;br /&gt;3:   Date visitDate = new Date()  &lt;br /&gt;4:   static belongsTo = [library:Library]  &lt;br /&gt;5:  }  &lt;br /&gt;6:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So far so good, or is it... what is the problem?&lt;br /&gt;&lt;br /&gt;For the hasMany relationship a hibernate Persistent Set is created by default.  A Set requires all of the elements in the Set be unique.  How would hibernate know if the new item is unique - without loading &lt;span style="font-weight:bold;"&gt;all&lt;/span&gt; of the elements to verify that it is unique?  The short answer is, it has to load all of the elements first.  Yes, all visits to the library - all of them.  This could number into the millions at some point.  Even if as a result of business rules we know that the Visit is unique. &lt;br /&gt;&lt;br /&gt;In hibernate, the relationship could have been modeled as a bag - but unfortunately GORM does not support a bag.&lt;br /&gt;&lt;br /&gt;Lets look at this and see if that is true.  Below is a unit test which demonstrates this.&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:    void testAddingLibraryVisits() {  &lt;br /&gt;2:     Library library = new Library(name:'LocalLibrary')  &lt;br /&gt;3:     int maxVisits = 100  &lt;br /&gt;4:    &lt;br /&gt;5:     (1..maxVisits).each {  &lt;br /&gt;6:      library.addToVisits(new Visit(personName:"person${it}"))  &lt;br /&gt;7:     }  &lt;br /&gt;8:     library.save()  &lt;br /&gt;9:     sessionFactory.getCurrentSession().flush()  &lt;br /&gt;10:     sessionFactory.getCurrentSession().clear()  &lt;br /&gt;11:    &lt;br /&gt;12:     assertEquals 1, Library.count()  &lt;br /&gt;13:     assertEquals maxVisits, Visit.count()  &lt;br /&gt;14:    &lt;br /&gt;15:     sessionFactory.getCurrentSession().flush()  &lt;br /&gt;16:     sessionFactory.getCurrentSession().clear()  &lt;br /&gt;17:    &lt;br /&gt;18:     println "============= Find the library ============="  &lt;br /&gt;19:    &lt;br /&gt;20:     Library newLibrary = Library.findById(library.id)  &lt;br /&gt;21:       &lt;br /&gt;22:     println "============= Create one more visit ============="  &lt;br /&gt;23:     Visit oneMoreVisit = new Visit(personName:"oneMorePerson")  &lt;br /&gt;24:     println "============= Add and Save one more visit ============="  &lt;br /&gt;25:     newLibrary.addToVisits(oneMoreVisit).save()  &lt;br /&gt;26:     println "============= Check number of visits in library ============="  &lt;br /&gt;27:     assertEquals maxVisits+1, newLibrary.visits.size()  &lt;br /&gt;28:       &lt;br /&gt;29:     sessionFactory.getCurrentSession().flush()  &lt;br /&gt;30:     sessionFactory.getCurrentSession().clear()  &lt;br /&gt;31:     println "============= Done adding one more visit ============="  &lt;br /&gt;32:    &lt;br /&gt;33:     println "============= Check count of libraries and visits ============="  &lt;br /&gt;34:     assertEquals 1, Library.count()  &lt;br /&gt;35:     assertEquals maxVisits+1, Visit.count()  &lt;br /&gt;36:    }  &lt;br /&gt;37:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lets look at each section.&lt;br /&gt;&lt;br /&gt;The first part, lines 1-17 just get data setup.  It is the other lines that are interesting.&lt;br /&gt;&lt;br /&gt;Lines18-20 which are summarized below with their SQL output.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  println "============= Find the library ============="  &lt;br /&gt;2:  Library newLibrary = Library.findById(library.id)  &lt;br /&gt;3:    &lt;br /&gt;4:  ============= Find the library =============  &lt;br /&gt;5:  Hibernate:   &lt;br /&gt;6:    select  &lt;br /&gt;7:      this_.id as id8_0_,  &lt;br /&gt;8:      this_.version as version8_0_,  &lt;br /&gt;9:      this_.name as name8_0_   &lt;br /&gt;10:    from  &lt;br /&gt;11:      library this_   &lt;br /&gt;12:    where  &lt;br /&gt;13:      this_.id=?  &lt;br /&gt;14:    &lt;br /&gt;15:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;After saving a 100 visits to the library, we get setup to add one more visit.  In line 2 above, we perform a 'findById' on the library.  You can see from the resulting query that the visits have not been loaded because by default all collections are lazy.&lt;br /&gt;&lt;br /&gt;Next we add a newly created visit to the collection.&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  println "============= Create one more visit ============="  &lt;br /&gt;2:  Visit oneMoreVisit = new Visit(personName:"oneMorePerson")  &lt;br /&gt;3:  println "============= Add and Save one more visit ============="  &lt;br /&gt;4:  newLibrary.addToVisits(oneMoreVisit).save()  &lt;br /&gt;5:    &lt;br /&gt;6:  ============= Create one more visit =============  &lt;br /&gt;7:  ============= Add and Save one more visit =============  &lt;br /&gt;8:  Hibernate:   &lt;br /&gt;9:    select  &lt;br /&gt;10:      visits0_.library_id as library3_1_,  &lt;br /&gt;11:      visits0_.id as id1_,  &lt;br /&gt;12:      visits0_.id as id2_0_,  &lt;br /&gt;13:      visits0_.version as version2_0_,  &lt;br /&gt;14:      visits0_.library_id as library3_2_0_,  &lt;br /&gt;15:      visits0_.person_name as person4_2_0_,  &lt;br /&gt;16:      visits0_.visit_date as visit5_2_0_   &lt;br /&gt;17:    from  &lt;br /&gt;18:      visit visits0_   &lt;br /&gt;19:    where  &lt;br /&gt;20:      visits0_.library_id=?  &lt;br /&gt;21:  Hibernate:   &lt;br /&gt;22:    insert   &lt;br /&gt;23:    into  &lt;br /&gt;24:      visit  &lt;br /&gt;25:      (id, version, library_id, person_name, visit_date)   &lt;br /&gt;26:    values  &lt;br /&gt;27:      (null, ?, ?, ?, ?)  &lt;br /&gt;28:  Hibernate:   &lt;br /&gt;29:    call identity()  &lt;br /&gt;30:  Hibernate:   &lt;br /&gt;31:    update  &lt;br /&gt;32:      library   &lt;br /&gt;33:    set  &lt;br /&gt;34:      version=?,  &lt;br /&gt;35:      name=?   &lt;br /&gt;36:    where  &lt;br /&gt;37:      id=?   &lt;br /&gt;38:      and version=?  &lt;br /&gt;39:  ============= Done adding one more visit =============  &lt;br /&gt;40:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In line 2 we create a new Visit instance, and in line4 we add this to the visits collection and save the library.&lt;br /&gt;&lt;br /&gt;Notice starting in line 8 - that we are loading all of the visits for the particular library.  This is where the issue comes into play.&lt;br /&gt;On line 21 the new visit record is being inserted into the visit table and finally on line 31 the Library instance is saved.&lt;br /&gt;&lt;br /&gt;I hope you can see that this could definitely be a performance issue.  It will work great in dev, and great in QA - but 1 month into production and this will be an issue.&lt;br /&gt;&lt;br /&gt;This concludes the database interaction to save one more item to a collection.  &lt;br /&gt;&lt;br /&gt;In my next blog post I will discuss what Burt suggested to address this problem, and a set of API changes to implement Burt's suggestion while keeping the unit test intact.&lt;br /&gt;&lt;br /&gt;Thanks for stopping by and stop by again to see the next blog post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-8316467226332944169?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/8316467226332944169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=8316467226332944169' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8316467226332944169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8316467226332944169'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/10/springone-2gx-conf-gorm-performance.html' title='SpringOne 2GX Conf - GORM Performance'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-8681058746834436111</id><published>2010-10-13T22:26:00.003-05:00</published><updated>2010-10-13T22:51:59.116-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Using the H2 Database CSVREAD with a sequence ID Column</title><content type='html'>The problem I was researching was the following:&lt;br /&gt;Make the contents of a csv file, a potentially very large csv file, available to a Grails web application and be able to query against the fields as though it were a database.&lt;br /&gt;&lt;br /&gt;I had a need to read a csv file and put this into a database so I could later query against it and the database had to persist across web application restarts.  My research ( which amounted to a bunch of google searches ) led me to the database H2.  You can find out more about H2 &lt;a href="http://www.h2database.com/html/main.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;More research led me to a pretty cool google code project called, &lt;a href="http://code.google.com/p/gcsvsql"&gt;gcsvsql&lt;/a&gt; which was a project that contained a groovy script to use H2, read the file(s) and put the data into an in memory database to query against on the command line or in a groovy shell.&lt;br /&gt;&lt;br /&gt;This was almost exactly what I needed.  I just needed to get this into a file based database because the data had to persist across restarts of the web application, and I really wanted an ID column.  The data had a business ID column, that was probably unique - but since I did not control it I really wanted a surrogate ID column.  Plus I originally thought I would use GORM and having an ID column just makes GORM life easier.&lt;br /&gt;&lt;br /&gt;What I ended up doing was to use much of the gcsvsql script, added some additional parameters for output database directory, table name to use, etc.  The important 5 lines are below.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  def sql = Sql.newInstance("jdbc:h2:file:${outputDir}/${tableName}","org.h2.Driver")  &lt;br /&gt;2:    &lt;br /&gt;3:  def seqstmt = "create sequence " + tableNameSeq + " start with 1"  &lt;br /&gt;4:    &lt;br /&gt;5:  def stmt = "create table $tableName(ID INT PRIMARY KEY, $columnTypes) as select (select " + tableNameSeq + ".nextval from dual), * from csvread('$pathToCsvFile')" as String  &lt;br /&gt;6:    &lt;br /&gt;7:  sql.execute(seqstmt)  &lt;br /&gt;8:    &lt;br /&gt;9:  sql.execute(stmt)  &lt;br /&gt;10:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In Line 1, I am just using Groovy Sql to establish a connection a database based on some input parameters.&lt;br /&gt;in Line 3, I am create a sequence that I am going to use to hold the primary key ID column values&lt;br /&gt;In Line 5, I am creating a new table in the database, from the input parameters using the sequence to generate the primary key ID field.&lt;br /&gt;&lt;br /&gt;Lines 7 and 9 just get the ball rolling after the setup.&lt;br /&gt;&lt;br /&gt;Why this blog posting?  Well - I never actually found a blog with this exact example of reading a csvfile into a file based H2 database and adding a new ID column based on a dynamically created sequence so I wanted to share back.  As I mentioned, I borrowed heavily from the gcsvsql script, so you should definitely check that out.&lt;br /&gt;&lt;br /&gt;If you want to see the entire script - leave me a comment and I will add the file to a future blog post along with my Groovy Sql reading of the data.&lt;br /&gt;&lt;br /&gt;I hope this was useful to someone out there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-8681058746834436111?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/8681058746834436111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=8681058746834436111' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8681058746834436111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8681058746834436111'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/10/using-h2-database-csvread-with-sequence.html' title='Using the H2 Database CSVREAD with a sequence ID Column'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-2256163305085989608</id><published>2010-09-05T17:58:00.004-05:00</published><updated>2010-09-05T18:23:15.080-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Groovy Categories for temporary mixins</title><content type='html'>In my previous post I showed how you could add the Apache StringUtils capability into the standard String class in BootStrap.groovy for the entire application to use.&lt;br /&gt;&lt;br /&gt;But what if for some reason you do not have access to BootStrap.groovy or adding this kind of mixin for everyone is a little egregious.&lt;br /&gt;&lt;br /&gt;This is where Groovy Categories come in very handy.  A Groovy 'Category' can be added to any class at runtime by using the 'use' Groovy keyword.&lt;br /&gt;&lt;br /&gt;Below is a simple unit test which shows how this is done very easly.&lt;br /&gt;&lt;br /&gt;Lines 2-6 show the typical Java usage( with a little Groovy thrown in) using StringUtils.  &lt;br /&gt;&lt;br /&gt;Lines 9 - 13 so the how the 'use' keyword can be used to temporarily mixin the StringUtils capabilities to a String.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:    void testUseCategory() {  &lt;br /&gt;2:     String testString = "break.this.string.up.into.words"  &lt;br /&gt;3:     println "Test StringUtils.split"  &lt;br /&gt;4:     StringUtils.split(testString, ".").each {  &lt;br /&gt;5:      println it  &lt;br /&gt;6:     }  &lt;br /&gt;7:    &lt;br /&gt;8:     println "Test use(StringUtils)"  &lt;br /&gt;9:     use(StringUtils) {  &lt;br /&gt;10:      testString.split(".").each {  &lt;br /&gt;11:       println it  &lt;br /&gt;12:      }  &lt;br /&gt;13:     }  &lt;br /&gt;14:    }  &lt;br /&gt;15:    &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This example shows how to take a third party library and mix it in, but you can also do this for your own utility classes.  You could create a utility class that operates on your class, and then 'use' that utility class to mix those methods in as though they exist on your class.  This helps to keep your class focused on the business problem and makes the class much easier to read.&lt;br /&gt;&lt;br /&gt;Just another example of some really cool Groovy capability.&lt;br /&gt;&lt;br /&gt;I don't always code - but when I do, I prefer Groovy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-2256163305085989608?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/2256163305085989608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=2256163305085989608' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/2256163305085989608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/2256163305085989608'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/09/groovy-categories-for-temporariy-mixins.html' title='Groovy Categories for temporary mixins'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-3028983818965383816</id><published>2010-08-22T21:22:00.006-05:00</published><updated>2010-08-22T21:43:18.976-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Adding StringUtils to the String Class in Groovy/Grails</title><content type='html'>This one has been blogged about before - but I thought it was just such an easy way to add very useful functionality to the String class that I thought I would call it out.&lt;br /&gt;&lt;br /&gt;I had the need to use the Apache StringUtils methods so often in my application that I started to wish that the methods were just native to the String class.  Adding this kind of capability is called mixins in Groovy.&lt;br /&gt;&lt;br /&gt;To check if a string is null, empty or whitespace, with the Apache package you have to write:&lt;br /&gt;&lt;br /&gt;If( StringUtils.isBlank( myStringToCheck) ) {&lt;br /&gt;// then is blank&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;what I wanted to do was:&lt;br /&gt;&lt;br /&gt;if( myStringToCheck.isBlank() ) {&lt;br /&gt;// then is blank&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;I just thought this was easier to read and easier to write.&lt;br /&gt;&lt;br /&gt;This is actually incredibly easy to do in Groovy/Grails.&lt;br /&gt;&lt;br /&gt;The way I went about do this was to add the following line of code to the Bootstrap.groovy file:&lt;br /&gt;&lt;br /&gt;    // add apache commons lang StringUtils methods to the String class&lt;br /&gt;    String.metaClass.mixin StringUtils&lt;br /&gt;&lt;br /&gt;add the commons-lang jar file to the lib directory and that is it.&lt;br /&gt;&lt;br /&gt;Now for any String I can use any of the methods in the StringUtils package as though they were native methods to the String class.&lt;br /&gt;&lt;br /&gt;Nice!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-3028983818965383816?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/3028983818965383816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=3028983818965383816' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/3028983818965383816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/3028983818965383816'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/08/adding-stringutils-to-string-class-in.html' title='Adding StringUtils to the String Class in Groovy/Grails'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-6864704871124838311</id><published>2010-05-05T00:23:00.002-05:00</published><updated>2010-05-05T00:42:30.408-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Grails: Dynamically adding a save method to Domain objects that show errors</title><content type='html'>I was writing some integration tests and I noticed that one of my asserts was failing on a save.  It was not clear to me why, so I started to add some diagnostic printing of errors.  Then I thought - what happens if another domain object has a problem saving?  Am I going to have to do this kind of error check all of the time?  Ugh..&lt;br /&gt;&lt;br /&gt;Using what I have already blogged about in terms of adding metaprogramming for Services, and a quick google search:  See this &lt;a href="http://stackoverflow.com/questions/611282/o-errors-allerrors-each-println-it-by-default-when-failing-to-save-a-domain-o"&gt;link&lt;/a&gt; where I got most of the inspiration.&lt;br /&gt;&lt;br /&gt;What I did was add the following method to Bootstrap.groovy.  &lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  def addDebugSaveToDomainObjects() {&lt;br /&gt;    grailsApplication.domainClasses.each {&lt;br /&gt;      it.metaClass.debugSave =  {&lt;br /&gt;        def obj = delegate.save()&lt;br /&gt;        if( obj == null ) {&lt;br /&gt;          println &amp;quot;Error saving &amp;quot; + delegate.getClass().name&lt;br /&gt;          delegate.errors.allErrors.each {&lt;br /&gt;            println it&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;        return obj&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The above code will add a new method to all Domain objects call debugSave.  If there is a problem while saving the domain object this new method will print all of the errors.  These errors can be seen in the junit reports.&lt;br /&gt;&lt;br /&gt;I did it this way because I really only want these methods when I am testing and I did not want to clutter the domain API with this debug code.&lt;br /&gt;&lt;br /&gt;In the bootstrap, I look at the environment and based on the environment name I will call the above closure ( or not as the case may be ).&lt;br /&gt;&lt;br /&gt;Next in my integration test, I can execute code like the following:&lt;br /&gt;&lt;br /&gt;def myDomain = new Domain(....)&lt;br /&gt;assertNotNull myDomain.debugSave()&lt;br /&gt;&lt;br /&gt;If the assert fails, then the Junit reports will tell me so and the output will tell me why.&lt;br /&gt;&lt;br /&gt;I hope you found this information useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-6864704871124838311?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/6864704871124838311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=6864704871124838311' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/6864704871124838311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/6864704871124838311'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/05/grails-dynamically-adding-save-method.html' title='Grails: Dynamically adding a save method to Domain objects that show errors'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-7535063291870936268</id><published>2010-03-30T21:12:00.003-05:00</published><updated>2010-05-02T14:46:05.741-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Grails: Intercepting Service class methods - part 3</title><content type='html'>Well - I have a couple of updates to my previous post:&lt;br /&gt;&lt;br /&gt;1) Grails 1.2.2 is out and it does look like the Spring DSL for AOP definitions is fixed.&lt;br /&gt;2) using the Spring xml definition in part 2 performed very poorly.  I am not sure why but if I changed the pointcut definition to:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;pointcut="execution(* com.redpointtech.flex..*Service..*(..))"&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;it performed MUCH better&lt;br /&gt;&lt;br /&gt;Given that the DSL is fixed and I needed it to perform better I have changed the AOP definition again to the following in the resources.groovy file.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; beans = {  &lt;br /&gt;  xmlns aop:"http://www.springframework.org/schema/aop"  &lt;br /&gt;   securityAspect(SecurityAspect)  &lt;br /&gt;   aop {  &lt;br /&gt;    config("proxy-target-class":true) {  &lt;br /&gt;     aspect(id:'theSecurityAspectDef', ref:'securityAspect') {  &lt;br /&gt;      around method: "invoke", pointcut:"execution(* com.redpointtech.flex..*Service..*(..))"  &lt;br /&gt;     }  &lt;br /&gt;    }  &lt;br /&gt;   }  &lt;br /&gt; }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I think this concludes my saga to get Flex services intercepted.  I hope this helps you out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-7535063291870936268?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/7535063291870936268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=7535063291870936268' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7535063291870936268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7535063291870936268'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/03/grails-intercepting-service-class_30.html' title='Grails: Intercepting Service class methods - part 3'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-8558446528519639560</id><published>2010-03-16T22:05:00.003-05:00</published><updated>2010-03-16T22:16:34.868-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Grails: Intercepting Service class methods - part 2</title><content type='html'>As a continuation from my earlier post about intercepting Grails Service methods - as it turns out that approach will not work when using flex-remoting.  If you want to intercept your services that you expose as Flex services you have to use Spring AOP.  Because of a bug: http://jira.codehaus.org/browse/GRAILS-5932 you will have to use the XML version of AOP definition.&lt;br /&gt;&lt;br /&gt;To do that you have to create a resources.xml file in grails-app/conf/spring directory and it would look like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; &amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;  &lt;br /&gt; &amp;lt;beans xmlns="http://www.springframework.org/schema/beans"  &lt;br /&gt;     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  &lt;br /&gt;     xmlns:aop="http://www.springframework.org/schema/aop"  &lt;br /&gt;     xsi:schemaLocation="  &lt;br /&gt; http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  &lt;br /&gt; http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"&amp;gt;  &lt;br /&gt;   &amp;lt;!--  &lt;br /&gt;     we are defining the AOP beans in the xml file because of this bug which will  &lt;br /&gt;     not be fixed until 1.2.2 and we are using 1.2.1  &lt;br /&gt;     http://jira.codehaus.org/browse/GRAILS-5932  &lt;br /&gt;     aspect are called twice because of the above bug. See  &lt;br /&gt;     http://n4.nabble.com/Advice-called-2-or-more-times-for-aspect-with-execution-pointcut-Bug-td1588831.html  &lt;br /&gt;     toward the bottom Graeme says that 1.2.2 will have the fixes, and 1.3 M1 already does have the  &lt;br /&gt;     fix. For now we have to live with the interceptor called twice.  &lt;br /&gt;   --&amp;gt;  &lt;br /&gt;   &amp;lt;bean id="myAroundAspect" class="com.redpointtech.aop.MyAroundAspect" /&amp;gt;  &lt;br /&gt;   &amp;lt;aop:config proxy-target-class="true"&amp;gt;  &lt;br /&gt;     &amp;lt;aop:aspect id="theAspect" ref="myAroundAspect"&amp;gt;  &lt;br /&gt;       &amp;lt;aop:around method="invoke" pointcut="target(com.redpointtech.aop.AOPMarkerInterface)" /&amp;gt;  &lt;br /&gt;     &amp;lt;/aop:aspect&amp;gt;  &lt;br /&gt;   &amp;lt;/aop:config&amp;gt;  &lt;br /&gt; &amp;lt;/beans&amp;gt;  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This assumes that you want to intercept any class that implements the AOPMarkerInterface.&lt;br /&gt;&lt;br /&gt;The Aspect looks like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; class MyAroundAspect {  &lt;br /&gt;  public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {  &lt;br /&gt;   Object returnVal = null  &lt;br /&gt;   println "MyAroundAspect called...."  &lt;br /&gt;   returnVal = joinPoint.proceed()  &lt;br /&gt;   return returnVal  &lt;br /&gt;  }  &lt;br /&gt; }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A couple of take aways:&lt;br /&gt;1) do not try to do what I suggested in my previous blog post.  That will NOT work for Flex services&lt;br /&gt;2) do not use resources.groovy and the Spring DSL - there is a bug in the 1.2.x version that prevents that from working.  This is suppose to be fixed in the 1.2.2 release ( not yet released) and the 1.3 M1 ( available now )&lt;br /&gt;3) do use resources.xml and define your Aspect the old fashion way - the old ways work just great.&lt;br /&gt;&lt;br /&gt;I hope this saves you some time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-8558446528519639560?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/8558446528519639560/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=8558446528519639560' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8558446528519639560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8558446528519639560'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/03/grails-intercepting-service-class_16.html' title='Grails: Intercepting Service class methods - part 2'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-2540201312322516495</id><published>2010-03-13T21:12:00.004-06:00</published><updated>2010-03-13T21:39:45.483-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Grails: Intercepting Service class methods</title><content type='html'>It took me a little while to fully understand how to add some kind of interceptor to a Grails Service class and I wanted to add a blog post incase others have a similar question.  After doing some research, and piecing together information from various sites I ended up with the information here.  I hope it is helpful to you.&lt;br /&gt;&lt;br /&gt;What problem am I trying to solve?&lt;br /&gt;Adding interceptors to Controllers is really easy and I wanted to add some interceptors to my Service classes in a similar fashion.  But it appears that you cannot do this for Service classes - just Controller classes.  If I am wrong, please someone show me how best to do this.&lt;br /&gt;&lt;br /&gt;Why am I trying to do this?&lt;br /&gt;I use Flex in many of my application implementations and I use BlazeDS/AMF in many of the cases.  I needed to add a security check on every exposed Flex service.&lt;br /&gt;&lt;br /&gt;How did I do this?&lt;br /&gt;In my service class I added a custom property that I called 'secureService'.  But as you will see you can use anything.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; class TeslaService {  &lt;br /&gt;   boolean transactional = true  &lt;br /&gt;  // secureService is a custom property that is looked for in the BootStrap.groovy file and if  &lt;br /&gt;  // found in a ServiceClass, then it modifies the invokeMethod to add some code before and  &lt;br /&gt;  // after the call.  &lt;br /&gt;   boolean secureService = true  &lt;br /&gt;   def serviceMethod() {  &lt;br /&gt;    println 'Tesla Service Method called'  &lt;br /&gt;   }  &lt;br /&gt; }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Next I updated my BootStrap.groovy file and for each ServiceClass, checked for the 'secureService' property being set to true.  If it was, I then used the MetaClass InvokeMethod and assigned a new closure that could add a security check.&lt;br /&gt;&lt;br /&gt;The updated bootstrap file looked like the following:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; class BootStrap {  &lt;br /&gt;    def grailsApplication  &lt;br /&gt;    def init = { servletContext -&amp;gt;  &lt;br /&gt;    grailsApplication.serviceClasses.each {  &lt;br /&gt;     def isSecured = it.getPropertyValue('secureService')  &lt;br /&gt;     if( isSecured ) {  &lt;br /&gt;      // example of how to 'intercept' service classes.  &lt;br /&gt;      it.metaClass.invokeMethod = { name, args -&amp;gt;  &lt;br /&gt;       println '''SECURE before $name'''  &lt;br /&gt;       def res = delegate.metaClass.getMetaMethod(name,args).invoke( delegate, args)  &lt;br /&gt;       println '''SECURE after $name. res=$res'''  &lt;br /&gt;       res  &lt;br /&gt;      }  &lt;br /&gt;     }  &lt;br /&gt;    }  &lt;br /&gt;    }  &lt;br /&gt;    def destroy = {  &lt;br /&gt;    }  &lt;br /&gt; }   &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To test this I created an Integration test.  This test looked like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; class TeslaServiceIntegrationTests extends GrailsUnitTestCase {  &lt;br /&gt;  def teslaService  &lt;br /&gt;   protected void setUp() {  &lt;br /&gt;     super.setUp()  &lt;br /&gt;   }  &lt;br /&gt;   protected void tearDown() {  &lt;br /&gt;     super.tearDown()  &lt;br /&gt;   }  &lt;br /&gt;   void testServiceMethod() {  &lt;br /&gt;    teslaService.serviceMethod()  &lt;br /&gt;   }  &lt;br /&gt; }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output of this was the following:&lt;br /&gt;SECURE before serviceMethod&lt;br /&gt;Tesla Service Method called&lt;br /&gt;SECURE after serviceMethod. res=null&lt;br /&gt;&lt;br /&gt;Some of the links that I used are below as the information from these posts might also be helpful to you.&lt;br /&gt;&lt;br /&gt;http://www.pubbs.net/grails/201001/9868/&lt;br /&gt;http://mrhaki.blogspot.com/2010/01/grails-goodness-access-grails.html&lt;br /&gt;http://www.grails.org/doc/latest/api/org/codehaus/groovy/grails/commons/ClassPropertyFetcher.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-2540201312322516495?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/2540201312322516495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=2540201312322516495' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/2540201312322516495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/2540201312322516495'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/03/grails-intercepting-service-class.html' title='Grails: Intercepting Service class methods'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-7058009379632134842</id><published>2010-01-05T23:52:00.003-06:00</published><updated>2010-01-06T00:05:06.491-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>FlexBuilder 3 and FlexUnit4 RC1</title><content type='html'>This will be a quick post on how to setup FlexBuilder project to use FlexUnit4.  This post will be more prescriptive with just the steps without a lot of explanation.  The FlexUnit site has good documentation.&lt;br /&gt;&lt;br /&gt;1) Setup a Flex Project as you normally would.&lt;br /&gt;2) Download the FlexUnit4 &lt;latest&gt; from this &lt;a href="http://opensource.adobe.com/wiki/display/flexunit/Downloads"&gt;link&lt;/a&gt;.&lt;br /&gt;3) Unzip and copy all of the swc files to your projects libs directory. There should be 4 swc files.&lt;br /&gt;4) create a package/folder under the src directory called flexUnitTests.  It could be called anything.&lt;br /&gt;5) Create a test Suite class.  This is just a POAO ( plain old actionscript object ).  I called mine FlexUnit4Suite and it looked like the following:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  package flexUnitTests  &lt;br /&gt;2:  {  &lt;br /&gt;3:      import org.flexunit.runners.Suite;  &lt;br /&gt;4:      [Suite]  &lt;br /&gt;5:      [RunWith("org.flexunit.runners.Suite")]   &lt;br /&gt;6:      public class FlexUnit4Suite  &lt;br /&gt;7:      {          &lt;br /&gt;8:          public var testCase1:MyTestCase;  &lt;br /&gt;9:      }  &lt;br /&gt;10:  }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Lines 4 and 5 are the most interesting.  Use the Suite and RunsWith metadata tags.  Line 8 is a reference to your TestCase class.  As you add more TestCase classes, just add a new variable here.  You dont have to instantiate it, or anything - just declare it.&lt;br /&gt;&lt;br /&gt;6) Create your TestCase class, which again is a POAO.  Mine looked like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  package flexUnitTests  &lt;br /&gt;2:  {  &lt;br /&gt;3:      import flexunit.framework.Assert;  &lt;br /&gt;4:      public class MyTestCase  &lt;br /&gt;5:      {  &lt;br /&gt;6:          public function MyTestCase()  &lt;br /&gt;7:          {  &lt;br /&gt;8:          }  &lt;br /&gt;9:          [BeforeClass]  &lt;br /&gt;10:          public static function runBeforeClass():void {  &lt;br /&gt;11:              trace("runBeforeClass");  &lt;br /&gt;12:          }  &lt;br /&gt;13:          [AfterClass]  &lt;br /&gt;14:          public static function runAfterClass():void {  &lt;br /&gt;15:              trace("runAfterClass");  &lt;br /&gt;16:          }  &lt;br /&gt;17:          [Before]  &lt;br /&gt;18:      public function runBeforeEveryTest():void   &lt;br /&gt;19:      {  &lt;br /&gt;20:        trace("runBeforeEveryTest");  &lt;br /&gt;21:      }  &lt;br /&gt;22:      [After]  &lt;br /&gt;23:      public function runAfterEveryTest():void   &lt;br /&gt;24:      {  &lt;br /&gt;25:          trace("runAfterEveryTest");  &lt;br /&gt;26:      }  &lt;br /&gt;27:      [Test]   &lt;br /&gt;28:      public function testTrue():void  &lt;br /&gt;29:      {  &lt;br /&gt;30:          trace("checkMethod");  &lt;br /&gt;31:          Assert.assertTrue( true );  &lt;br /&gt;32:      }  &lt;br /&gt;33:          [Ignore("Not Ready to Run")]  &lt;br /&gt;34:      [Test]  &lt;br /&gt;35:      public function testNotReady():void   &lt;br /&gt;36:      {  &lt;br /&gt;37:        Assert.assertFalse( true );  &lt;br /&gt;38:      }          &lt;br /&gt;39:      }  &lt;br /&gt;40:  }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;7) Create a new Application for the test runner.  You dont have to create a new application, but I assume you already have an Application class that really runs your application.  I created another Application called FlexUnitTestRunner.  It looked like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  &amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;  &lt;br /&gt;2:  &amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"  &lt;br /&gt;3:      xmlns:flexunitrunning="http://www.adobe.com/2009/flexUnitUIRunner"  &lt;br /&gt;4:      minWidth="1024" minHeight="768" creationComplete="onCreationComplete()"&amp;gt;  &lt;br /&gt;5:      &amp;lt;mx:Script&amp;gt;  &lt;br /&gt;6:          &amp;lt;![CDATA[  &lt;br /&gt;7:              import flexUnitTests.FlexUnit4Suite;  &lt;br /&gt;8:              import org.flexunit.listeners.UIListener;  &lt;br /&gt;9:              import org.flexunit.runner.FlexUnitCore;  &lt;br /&gt;10:              private var flexUnitCore:FlexUnitCore;  &lt;br /&gt;11:              private function onCreationComplete():void {  &lt;br /&gt;12:                  flexUnitCore = new FlexUnitCore();  &lt;br /&gt;13:                  flexUnitCore.addListener(new UIListener( testRunner));  &lt;br /&gt;14:                  flexUnitCore.run(FlexUnit4Suite);  &lt;br /&gt;15:              }  &lt;br /&gt;16:          ]]&amp;gt;  &lt;br /&gt;17:      &amp;lt;/mx:Script&amp;gt;  &lt;br /&gt;18:      &amp;lt;flexunitrunning:TestRunnerBase id="testRunner" width="100%" height="100%" /&amp;gt;  &lt;br /&gt;19:  &amp;lt;/mx:Application&amp;gt;  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Run the FlexUnitTestRunner application and my console output looked like:&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  runBeforeClass  &lt;br /&gt;2:  runBeforeEveryTest  &lt;br /&gt;3:  checkMethod  &lt;br /&gt;4:  runAfterEveryTest  &lt;br /&gt;5:  runAfterClass  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and a browser window popped up with the results of my test case.&lt;br /&gt;&lt;br /&gt;Thats it in a nutshell how to get a Flex Builder 3, sdk 3.5, FlexUnit4 up and running quickly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-7058009379632134842?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/7058009379632134842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=7058009379632134842' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7058009379632134842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7058009379632134842'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/01/flexbuilder-3-and-flexunit4-rc1.html' title='FlexBuilder 3 and FlexUnit4 RC1'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-1543237683086966296</id><published>2010-01-03T18:02:00.006-06:00</published><updated>2010-01-03T19:24:49.567-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AIR'/><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='FlexORM'/><title type='text'>FlexORM</title><content type='html'>What seems like many years ago now, because it was - I saw a presentation by Christophe Coenraets where he talked about a simple ORM for AIR.  You can see the original blog post &lt;a href="http://coenraets.org/blog/2007/10/annotating-actionscript-classes-with-custom-metadata-simple-orm-framework-for-air/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have used Hibernate for many years, and now most recently GORM and I am a big fan of ORM tools when used right and in the right measure.&lt;br /&gt;&lt;br /&gt;When I started looking at an AIR application I decided to revisit the work done in that original blog posting and I was very pleased to see that work had continued on with the ORM mapping, now called FlexORM. (Which is an interesting name since it only works with AIR ).  You can find more information about the FlexORM tool &lt;a href="http://flexorm.riaforge.org/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;What I am going to do is present some examples of how I used it.  I am hoping that my examples will help answer your questions on how to use the tool or inspire you start using it.&lt;br /&gt;&lt;br /&gt;In my simple application my domain model is one where a Project can have sub-projects to form a project hierarchy and each project can have many TimeEntry references but a TimeEntry is only allocated to a single Project.&lt;br /&gt;&lt;br /&gt;Lets look at the Project domain class first.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.domain&lt;br /&gt;{&lt;br /&gt;  import mx.collections.ArrayCollection;&lt;br /&gt;  import mx.collections.IList;&lt;br /&gt;&lt;br /&gt;  [Bindable]&lt;br /&gt;  [Table( name=&amp;quot;PROJECT&amp;quot;)]&lt;br /&gt;  public class Project&lt;br /&gt;  {&lt;br /&gt;    // each project can contain a number of child or&lt;br /&gt;    // sub projects.&lt;br /&gt;    private var _subProjects:IList = new ArrayCollection();&lt;br /&gt;    private var _timeEntries:IList = new ArrayCollection();&lt;br /&gt;    &lt;br /&gt;    [Id]&lt;br /&gt;    public var id:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;proj_name&amp;quot;)]&lt;br /&gt;    public var name:String;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;proj_desc&amp;quot;)]&lt;br /&gt;    public var desc:String;&lt;br /&gt;    &lt;br /&gt;    [Column(name=&amp;quot;color&amp;quot;)]&lt;br /&gt;    public var color:Number;&lt;br /&gt;    &lt;br /&gt;    [ManyToOne(name=&amp;quot;parent_id&amp;quot;, inverse=&amp;quot;true&amp;quot;)]&lt;br /&gt;    public var parent:Project;&lt;br /&gt;    &lt;br /&gt;    [OneToMany(type=&amp;quot;com.redpointtech.domain.Project&amp;quot;, fkColumn=&amp;quot;parent_id&amp;quot;, lazy=&amp;quot;false&amp;quot;, cascade=&amp;quot;save-update&amp;quot;, indexed=&amp;quot;true&amp;quot;)]&lt;br /&gt;    public function set subProjects(value:IList):void {&lt;br /&gt;      _subProjects = value;&lt;br /&gt;    }&lt;br /&gt;    public function get subProjects():IList {&lt;br /&gt;      return _subProjects;&lt;br /&gt;    }&lt;br /&gt;    public function addSubProject(value:Project):void {&lt;br /&gt;      value.parent = this;&lt;br /&gt;      _subProjects.addItem(value);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    [OneToMany(type=&amp;quot;com.redpointtech.domain.TimeEntry&amp;quot;, fkColumn=&amp;quot;project_id&amp;quot;, lazy=&amp;quot;true&amp;quot;, cascade=&amp;quot;all&amp;quot;, indexed=&amp;quot;true&amp;quot;)]&lt;br /&gt;    public function set timeEntries(value:IList):void {&lt;br /&gt;      _timeEntries = value;&lt;br /&gt;    }&lt;br /&gt;    public function get timeEntries():IList {&lt;br /&gt;      return _timeEntries;&lt;br /&gt;    }&lt;br /&gt;    public function addTimeEntry(value:TimeEntry):void {&lt;br /&gt;      value.project = this;&lt;br /&gt;      _timeEntries.addItem(value);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;    public function Project()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The primary metadata tags I used user:&lt;br /&gt;[Table( name="tbd")] to define the table name for the domain object.&lt;br /&gt;&lt;br /&gt;[Id] to tell the ORM which field is used for an id.  As of right now the id value must be of type 'int'.&lt;br /&gt;&lt;br /&gt;[Column( name="tbd")] to define the column name for a property.  If the name field is not specified then it uses the property name.&lt;br /&gt;&lt;br /&gt;[ManyToOne(name="col name", inverse="true/false")] to define the ManyToOne relationship with itself.  &lt;br /&gt;&lt;br /&gt;[OneToMany(...)] metadata tag is specific on the set/get methods.  Also noticed that we added an 'add' method which sets the parent of the Project and adds the Project to the collection of sub projects.&lt;br /&gt;&lt;br /&gt;The TimeEntry class looks like the following:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.domain&lt;br /&gt;{&lt;br /&gt;  import com.redpointtech.util.Constants;&lt;br /&gt;&lt;br /&gt;  [Bindable]&lt;br /&gt;  [Table( name=&amp;quot;TIMEENTRY&amp;quot;)]&lt;br /&gt;  public class TimeEntry&lt;br /&gt;  {&lt;br /&gt;    &lt;br /&gt;    [Id]&lt;br /&gt;    public var id:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;full_year&amp;quot;)]&lt;br /&gt;    public var fullYear:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;month&amp;quot;)]&lt;br /&gt;    public var month:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;day_of_month&amp;quot;)]&lt;br /&gt;    public var dayOfMonth:int; // Date.date equivalent&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;start_hour&amp;quot;)]&lt;br /&gt;    public var startHour:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;start_min&amp;quot;)]&lt;br /&gt;    public var startMin:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;end_hour&amp;quot;)]&lt;br /&gt;    public var endHour:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;end_min&amp;quot;)]&lt;br /&gt;    public var endMin:int;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;notes&amp;quot;)]&lt;br /&gt;    public var notes:String=&amp;quot;&amp;quot;;&lt;br /&gt;    &lt;br /&gt;    [Column( name=&amp;quot;summary&amp;quot;)]&lt;br /&gt;    public var summary:String=&amp;quot;&amp;quot;;&lt;br /&gt;    &lt;br /&gt;    [ManyToOne(name=&amp;quot;project_id&amp;quot;, inverse=&amp;quot;true&amp;quot;)]&lt;br /&gt;    public var project:Project;&lt;br /&gt;    &lt;br /&gt;    public function TimeEntry()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function setDate(date:Date):void {&lt;br /&gt;      fullYear = date.fullYear;&lt;br /&gt;      month = date.month;&lt;br /&gt;      dayOfMonth = date.date;&lt;br /&gt;      &lt;br /&gt;    }&lt;br /&gt;    public function setStartTime( hour:int, min:int):void {&lt;br /&gt;      startHour = hour;&lt;br /&gt;      startMin = min;&lt;br /&gt;    }&lt;br /&gt;    public function getStartDate():Date {&lt;br /&gt;      var startDate:Date = new Date(fullYear, month,dayOfMonth,startHour,startMin);&lt;br /&gt;      return startDate;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public function setEndTime(hour:int, min:int):void {&lt;br /&gt;      endHour = hour;&lt;br /&gt;      endMin = min;      &lt;br /&gt;    }&lt;br /&gt;    public function getEndDate():Date {&lt;br /&gt;      var endDate:Date = new Date(fullYear,month,dayOfMonth,endHour,endMin);&lt;br /&gt;      return endDate;&lt;br /&gt;      &lt;br /&gt;    }&lt;br /&gt;    private function _getTimeDiffInMillis():Number {&lt;br /&gt;      var startDate:Date = getStartDate();&lt;br /&gt;      &lt;br /&gt;      var endDate:Date = getEndDate();      &lt;br /&gt;      &lt;br /&gt;      var diff:Number = endDate.getTime() - startDate.getTime();&lt;br /&gt;&lt;br /&gt;      return diff;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    [Transient]&lt;br /&gt;    public function get elapsedHours():Number {&lt;br /&gt;      var diff:Number = _getTimeDiffInMillis();&lt;br /&gt;      &lt;br /&gt;      var hours:Number = diff / Constants.millisecondsPerHour;&lt;br /&gt;      &lt;br /&gt;      var floorHours:Number = Math.floor(hours);&lt;br /&gt;      &lt;br /&gt;      &lt;br /&gt;      return floorHours;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    [Transient]&lt;br /&gt;    public function get elapsedMinutes():Number {&lt;br /&gt;      var hours:Number = elapsedHours;&lt;br /&gt;      var milliHours:Number = hours * Constants.millisecondsPerHour;&lt;br /&gt;      &lt;br /&gt;      var diff:Number = _getTimeDiffInMillis();&lt;br /&gt;      &lt;br /&gt;      var minuteDiff:Number = diff - ( milliHours );&lt;br /&gt;      &lt;br /&gt;      var minutes:Number = minuteDiff / Constants.millisecondsPerMinute;&lt;br /&gt;      var roundedMinutes:Number = Math.min(Math.round(minutes),59);&lt;br /&gt;      return roundedMinutes;&lt;br /&gt;      &lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The only real difference is the use of Transient to tell FlexORM that these are not used in the persistence of the object.&lt;br /&gt;&lt;br /&gt;Now that we have a feel for how to annotate our domain classes to be used by FlexORM, lets see how to persist them to the database.&lt;br /&gt;&lt;br /&gt;I am using FlashBuilder Beta2 with FlexUnit4 RC1.  I will go over the integration of FlashBuilder and FlexUnit in another blog posting.  For this one I wanted to remain focused on using FlexORM.&lt;br /&gt;&lt;br /&gt;Below is a unit test function to test Project CRUD ( create read update delete )&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    [Test]&lt;br /&gt;    public function testCRUDNoHier():void {&lt;br /&gt;      trace(&amp;quot;----------------testCRUDNoHier----------------&amp;quot;);&lt;br /&gt;      var em:EntityManager = EntityManager.instance;&lt;br /&gt;&lt;br /&gt;      var p:Project = new Project();&lt;br /&gt;      p.name=&amp;quot;P1&amp;quot;;&lt;br /&gt;      p.desc = &amp;quot;proj from unit test&amp;quot;;&lt;br /&gt;      p.color=0xFF001E;&lt;br /&gt;      &lt;span style="font-weight:bold;"&gt;em.save(p);&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;      Assert.assertEquals(&amp;quot;P1&amp;quot;,p.name);&lt;br /&gt;      &lt;br /&gt;      var p2:Project = new Project();&lt;br /&gt;      p2.name=&amp;quot;P2&amp;quot;;&lt;br /&gt;      p2.desc = &amp;quot;proj2 from unit test&amp;quot;;&lt;br /&gt;      p2.color=0xAAAAAA;&lt;br /&gt;      &lt;span style="font-weight:bold;"&gt;em.save(p2);&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;      Assert.assertEquals(&amp;quot;P2&amp;quot;,p2.name);&lt;br /&gt;      Assert.assertEquals(&amp;quot;P1&amp;quot;,p.name);&lt;br /&gt;&lt;br /&gt;      var p1:Project = &lt;span style="font-weight:bold;"&gt;em.loadItem(Project, p.id) as Project;&lt;/span&gt;&lt;br /&gt;      Assert.assertEquals(&amp;quot;P1&amp;quot;,p1.name);&lt;br /&gt;      &lt;br /&gt;      var ps:ArrayCollection = em.findAll(Project);&lt;br /&gt;      Assert.assertEquals(2,ps.length);&lt;br /&gt;      &lt;br /&gt;      p1.desc = &amp;quot;New P1 desc&amp;quot;;&lt;br /&gt;      em.save(p1);&lt;br /&gt;      &lt;br /&gt;      var p3:Project = &lt;span style="font-weight:bold;"&gt;em.loadItem(Project,p1.id) as Project;&lt;/span&gt;&lt;br /&gt;      Assert.assertEquals(&amp;quot;New P1 desc&amp;quot;, p3.desc);&lt;br /&gt;      &lt;br /&gt;      &lt;span style="font-weight:bold;"&gt;em.remove(p2);&lt;/span&gt;&lt;br /&gt;      ps = em.findAll(Project);&lt;br /&gt;      Assert.assertEquals(1,ps.length);&lt;br /&gt;      &lt;br /&gt;      &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We start the test method by getting a reference to the EntityManager via EntityManager.instance.  The first thing we do in the test case, is to create a Project and the save it to the DB via the em.save(p).  &lt;br /&gt;&lt;br /&gt;That is all you have to do to save an entity, you do not need to write any sql yet.&lt;br /&gt;&lt;br /&gt;To load an item for which you have the id, you use the loadItem method passing in the Project class and the id value.  &lt;br /&gt;&lt;br /&gt;To find all records for a particular class, you use the findAll method.&lt;br /&gt;&lt;br /&gt;FlexORM even has a Criteria API.  While it is not on the same level as the Hibernate Criteria, it is still very useful.&lt;br /&gt;&lt;br /&gt;Below is an example method to find TimeEntries on a particular day:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    public static function findAllOn(fullYear:Number,month:Number=-1,dayOfMonth:Number=-1):ArrayCollection {&lt;br /&gt;      var teCriteria:Criteria = entityManager.createCriteria(TimeEntry);&lt;br /&gt;      teCriteria.addEqualsCondition(&amp;quot;fullYear&amp;quot;, fullYear);&lt;br /&gt;      if( month &amp;gt; -1 ) teCriteria.addEqualsCondition(&amp;quot;month&amp;quot;,month);&lt;br /&gt;      if( dayOfMonth &amp;gt; -1 ) teCriteria.addEqualsCondition(&amp;quot;dayOfMonth&amp;quot;,dayOfMonth);&lt;br /&gt;      teCriteria.addSort(&amp;quot;startHour&amp;quot;);&lt;br /&gt;      &lt;br /&gt;      return entityManager.fetchCriteria(teCriteria);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You use the EntityManager to create the criteria for an annotated class.  In this example I am using simple conditions to see that the TimeEntry has values that equal those passed in, and then sort the returned values based on the starting hour.&lt;br /&gt;&lt;br /&gt;Again - so far I have created no sql myself.  I am sure I will have a case where I need to hand craft some sql, and this will be fairly easy even with the EntityManager.  &lt;br /&gt;&lt;br /&gt;The idea behind the ORM tools, IMHO, is not to take over all of the persistence work but instead take over the mundane and tedious persistence work so we can concentrate on the more difficult tasks.  So far FlexORM has done that.&lt;br /&gt;&lt;br /&gt;I hope this quick example was useful in getting you interested in looking at FlexORM.  &lt;br /&gt;&lt;br /&gt;Next time I will discuss how I used FlashBuilder Beta2 and FlexUnit to test the application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-1543237683086966296?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/1543237683086966296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=1543237683086966296' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/1543237683086966296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/1543237683086966296'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2010/01/flexorm.html' title='FlexORM'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-8388239115912668034</id><published>2009-09-29T20:37:00.009-05:00</published><updated>2009-09-29T21:17:42.567-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>Designing the Obvious</title><content type='html'>Adobe MAX2009 is coming up this weekend, and while I won't get the chance to go this year I was reviewing some of the material from years past.  One presentation that I have somehow hung onto was one by Robert Hoekman Jr on 'Designing the Obvious' - from his book of the same name.&lt;br /&gt;&lt;br /&gt;I never got the book - but I think I will now.  As I was reading through the paper, he talks about something we all still come across everyday - form fields with character length limits.&lt;br /&gt;&lt;br /&gt;He mentions some of the 'obviously' wrong ways to do this:&lt;br /&gt;1) type in the field, hit submit and the system tells you that you guess wrong and that there were too many characters in the field.&lt;br /&gt;2) There is a 'hint' next to the text field but it lets you type in the wrong number of characters anyways.  He also noted that a 'hint' is not instructive to tell someone that spaces are or are not counted.&lt;br /&gt;3) The field just lets you type in characters until it just stops.  The 'stops' feedback still leaves us to wonder why the system stopped taking input.&lt;br /&gt;&lt;br /&gt;The 'obvious' answer he suggests is to give the user real-time feedback about their input.  As his book title suggests - this is so obvious.&lt;br /&gt;&lt;br /&gt;I thought I would create a quick component that did just that - gave the user real-time feedback on their input and accounted for either including space or excluding space.&lt;br /&gt;&lt;br /&gt;In the example application below, the first input just stops taking input at the maximum character - can you guess what that limit might be?  The second input uses a StringValidator - which is a step in the right direction, but does not provide the real-time feedback.  &lt;br /&gt;&lt;br /&gt;The next two use a simple component I created.  The first of those, has a 15 character limit, and spaces count toward that limit.  The next one has a 30 character limit and spaces do not count toward the limit.&lt;br /&gt;&lt;br /&gt;Getting the component to ignore spaces was trickier than I thought it would be at first - but for those curious you can download the code and see how I did this.&lt;br /&gt;&lt;br /&gt;Source can be found by clicking &lt;a href="http://www.theyoungsouls.com/blogs/redpoint/flexexamples/RedpointBlogPosts.zip"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed pluginspage=" http://www.macromedia.com/go/getflashplayer" src="http://www.theyoungsouls.com/blogs/redpoint/flexexamples/RedpointMaxLengthTextInput.swf" width="600" height="250" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;Thanks for stopping by.  I would love to hear your comments on the 'obvious'.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-8388239115912668034?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/8388239115912668034/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=8388239115912668034' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8388239115912668034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/8388239115912668034'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/09/designing-obvious.html' title='Designing the Obvious'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-634340573295350105</id><published>2009-05-23T18:58:00.010-05:00</published><updated>2009-05-23T19:31:02.057-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='BlazeDS'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Converting a Java/Flex application to Grails/Flex</title><content type='html'>I have a small reference application  to CRUD ( create, read, update and delete ) notes from a back end service using a simple flex application.  This reference application was originally written with Spring 2.5, later upgraded to 3, and Hibernate 3.x with MySql 5.  As new versions of these technologies come out, I integrate it into this simple reference application.  I use it as a sanity check while integrating all of those technologies because the application is not too difficult.&lt;br /&gt;&lt;br /&gt;I decided to try to migrate it to a Grails platform to get a sense for how difficult that might be.  I am going to share the steps that I took to migrate my Tomcat/Spring3/Hibernate3/MySql5 application to Grails/MySql5.&lt;br /&gt;&lt;br /&gt;Since I already had a database schema from the Java implementation I decide to leverage that DDL so that both applications could run against the same backend.&lt;br /&gt;&lt;br /&gt;Since I knew that the user interface was a Flex interface, I installed the flex plugin.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;grails install-plugin flex&lt;/span&gt;&lt;br /&gt;This plugin allows one to expose a Grails service as a Flex BlazeDS service by simply adding: &lt;span style="font-style:italic;"&gt;static expose = ['flex-remoting']&lt;/span&gt; to the service.&lt;br /&gt;&lt;br /&gt;The 3 methods that the Java service exposed were:&lt;br /&gt;* getAllNotes&lt;br /&gt;* saveOrUpdateNote&lt;br /&gt;* deleteNode&lt;br /&gt;&lt;br /&gt;Therefore, to maintain the same Flex UI I needed to expose the same API.&lt;br /&gt;&lt;br /&gt;The service ultimately ended up looking like the following:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.services&lt;br /&gt;import com.redpointtech.domain.Note&lt;br /&gt;class RedpointNotesService {&lt;br /&gt;&lt;br /&gt;    boolean transactional = true&lt;br /&gt;    static expose = ['flex-remoting']&lt;br /&gt;&lt;br /&gt;    def getAllNotes() {&lt;br /&gt;        def allNotes = Note.findAll()&lt;br /&gt;        return allNotes&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    def saveOrUpdateNote(Note note) {&lt;br /&gt;        def noteid = note.id&lt;br /&gt;        println &amp;quot;NOTE ID TO SAVE: &amp;quot; + noteid&lt;br /&gt;        // until I can figure out how to get unsavedValue:0 to&lt;br /&gt;        // work I need to do my own unsaved value.&lt;br /&gt;        if( noteid == 0 ) {&lt;br /&gt;            note.id = null;&lt;br /&gt;        }&lt;br /&gt;        note.save()&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    def deleteNote(Long noteId) {&lt;br /&gt;        def note = Note.findById(nodeId)&lt;br /&gt;        note?.delete()&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Take special note of the check for a zero noteid.  I could not immediately figure out how to tell grails that the 'unsaved-value' is 0 instead of the default null, so I had to make that programmatic.  I am still looking into this, but if you know the answer please leave a comment.&lt;br /&gt;&lt;br /&gt;To my pleasant surprise, the service was very small and the only extra work to expose the service to Flex was to add the 'static expose = ['flex-remoting']'.  Anyone that has exposed Flex services knows that you have to add a servlet to the web.xml, update the flex-remote.xml, add a Spring factory to get the service.  While not hard, certainly  more work that added one line to a service.  Please note, that I did NOT update the web.xml at all.&lt;br /&gt;&lt;br /&gt;Next I turned my attention to the Note domain object.  I used the the grails create-domain command to create the Note domain object.&lt;br /&gt;&lt;br /&gt;To keep this as minimal as possible to start I did not add any constraints - clearly you would normally.&lt;br /&gt;&lt;br /&gt;The Note domain class just keeps track of the authors name, the text of the note and the date the note was created.  There is no mapping to a User domain object because I purposefully wanted to keep this reference application very simple.&lt;br /&gt;&lt;br /&gt;Below is the Grails domain object:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.domain&lt;br /&gt;class Note{&lt;br /&gt;&lt;br /&gt;    //Long id&lt;br /&gt;    String author&lt;br /&gt;    String text&lt;br /&gt;    Date createDate&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    static mapping = {&lt;br /&gt;        table 'notes'&lt;br /&gt;        version false&lt;br /&gt;        id unsavedValue: 0&lt;br /&gt;        text column: &amp;quot;note_text&amp;quot;&lt;br /&gt;        createDate column: &amp;quot;create_date&amp;quot;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There are a couple of aspects to note:&lt;br /&gt;* I commented out the id property because by convention Grails gives every domain object an id property.&lt;br /&gt;* I had to add a mapping section because I was not able to use the grails default values.&lt;br /&gt;&lt;br /&gt;If you look up at the service class again, you will see methods on the Note class like 'findAll' but you do not see them here.  This is because GORM, which is Grails' Object Relational Mapping which sits on top of hibernate, creates many of the standard methods for you and dynamically adds them at runtime.  This dramatically decreases the number of DAO methods you need to write - and really all but eliminates the DAO layer all together.&lt;br /&gt;&lt;br /&gt;At this point, I now I have a service and a domain object that represents the Notes.  Because I am using a MySql database and not the supported out of the box HSQL DB, I have a little more configuration to do.&lt;br /&gt;&lt;br /&gt;The grails-app/conf/DataSource.groovy file contains the datasource definitions for all of the environments.&lt;br /&gt;&lt;br /&gt;Below is the version of DataSource.groovy that I used:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;dataSource {&lt;br /&gt;    pooled = true&lt;br /&gt;    driverClassName = &amp;quot;org.hsqldb.jdbcDriver&amp;quot;&lt;br /&gt;    username = &amp;quot;sa&amp;quot;&lt;br /&gt;    password = &amp;quot;&amp;quot;&lt;br /&gt;}&lt;br /&gt;hibernate {&lt;br /&gt;    cache.use_second_level_cache=true&lt;br /&gt;    cache.use_query_cache=true&lt;br /&gt;    cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'&lt;br /&gt;}&lt;br /&gt;// environment specific settings&lt;br /&gt;environments {&lt;br /&gt;    development {&lt;br /&gt;        dataSource {&lt;br /&gt;            pooled = false&lt;br /&gt;            driverClassName = &amp;quot;com.mysql.jdbc.Driver&amp;quot;&lt;br /&gt;            dbCreate = &amp;quot;update&amp;quot; // one of 'create', 'create-drop','update'&lt;br /&gt;            url = &amp;quot;jdbc:mysql://localhost/test&amp;quot;&lt;br /&gt;            username = &amp;quot;root&amp;quot;&lt;br /&gt;            password = &amp;quot;root&amp;quot;&lt;br /&gt;            logSql=&amp;quot;true&amp;quot;&lt;br /&gt;            dialect = org.hibernate.dialect.MySQL5InnoDBDialect&lt;br /&gt;        }&lt;br /&gt;        hibernate {&lt;br /&gt;            show_sql = true&lt;br /&gt;            hibernate.format_sql = true&lt;br /&gt;        } &lt;br /&gt;    }    &lt;br /&gt;    hsqldevelopment {&lt;br /&gt;        dataSource {&lt;br /&gt;            dbCreate = &amp;quot;create-drop&amp;quot; // one of 'create', 'create-drop','update'&lt;br /&gt;            url = &amp;quot;jdbc:hsqldb:mem:devDB&amp;quot;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    test {&lt;br /&gt;        dataSource {&lt;br /&gt;            dbCreate = &amp;quot;update&amp;quot;&lt;br /&gt;            url = &amp;quot;jdbc:hsqldb:mem:testDb&amp;quot;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    production {&lt;br /&gt;        dataSource {&lt;br /&gt;            dbCreate = &amp;quot;update&amp;quot;&lt;br /&gt;            url = &amp;quot;jdbc:hsqldb:file:prodDb;shutdown=true&amp;quot;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;You can see in the environments section, I altered the development datasource to use MySql instead of HSQL.  This should be pretty standard datasource configuration for MySql.&lt;br /&gt;&lt;br /&gt;The last thing I needed to do was drop the mysql JDBC jar into the lib directory - and it was complete.&lt;br /&gt;&lt;br /&gt;In the end I went from absolute zero, to a working Grails application that gave me the same functionality as my Tomcat/Spring/Hibernate application in less than an hour.  I have to say, I was very impressed with the speed of development in the grails environment.&lt;br /&gt;&lt;br /&gt;My company is currently working on a full featured, consumer facing Flex/Grails application and Grails has still not let me down even in this more challenging real world environment.&lt;br /&gt;&lt;br /&gt;Every time I use Grails, I am more convinced of its viability as a production ready framework.  It probably helps that it is built upon production ready frames of Spring and Hibernate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-634340573295350105?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/634340573295350105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=634340573295350105' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/634340573295350105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/634340573295350105'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/05/converting-javaflex-application-to.html' title='Converting a Java/Flex application to Grails/Flex'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-3916429340811330930</id><published>2009-03-29T17:11:00.024-05:00</published><updated>2009-03-29T18:16:06.440-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Creating a Grails Plugin for DBUnit</title><content type='html'>A colleague of mine &lt;a href="http://ericbweimer.blogspot.com/"&gt;Eric Weimer&lt;/a&gt; introduced me to Grails.  I had already used Groovy to a limited degree but not Grails.  Eric presented at the &lt;a href="http://www.cgug.org/"&gt;Chicago Groovy Users Group&lt;/a&gt; and I really wanted to learn more about Grails.  &lt;br /&gt;&lt;br /&gt;So I bought the book &lt;span style="font-style:italic;"&gt;The Definitive Guide to Grails - 2nd Edition&lt;/span&gt; which I highly recommend.  After getting through nearly all of the book, I really wanted to start working with Grails, so I took the example from the book and extended the Domain model slightly.  The area that I wanted to focus on for now was to get a better understanding of GORM, which is the ORM layer that uses Hibernate. &lt;br /&gt;&lt;br /&gt;To do this I created a simple Grails application with just Domain classes and I started to create some integration tests that I could use to get a feel for the GORM api.  &lt;br /&gt;&lt;br /&gt;However, to do this I quickly ended up needing to seed the database with some data so I could execute queries.  In my Java bag of tricks, I have used &lt;a href="http://www.dbunit.org/"&gt;DBUnit&lt;/a&gt; and I immediately wanted to leverage this in my Grails work.  Normally I would have checked to see if there was already a DBUnit Grails plugin, but I was actually in 'a dead zone' - and did not have internet access.  But this was ok - I already had all of the DBUnit code I needed from my Java projects.&lt;br /&gt;&lt;br /&gt;What this blog posting is going to show is how I used the information from the Grails book to create my own DBUnit plugin that I can now leverage in my projects.  As it turns out, there is already a DBUnit plugin and I will either submit my version or work with the author of that plugin to see about integrating some of my features into his code base.  This is my first venture into Grails - so if someone out there sees a better way to tackle this kind of problem please post a comment so we can all benefit.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 1 - create a plugin application&lt;/span&gt;&lt;br /&gt;grails create-plugin dbunit&lt;br /&gt;&lt;br /&gt;This will create what looks like a typical Grails application.  The only real difference is a file in the root directory of the project called: DbunitGrailsPlugin.groovy&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 2 - Update DbunitGrailsPlugin.groovy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Besides the author,title, etc information the only section I changed was the &lt;span style="font-style:italic;"&gt;doWithSpring&lt;/span&gt; closure.  I decided to take the utility class that I already had for my Java development, and create a Spring bean out of it.  This Spring bean can then be used in the Grails integration tests.  Below is the updated doWithSpring closure.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def doWithSpring = {&lt;br /&gt;        dbunitUtil(com.redpointtech.dbunit.DBUnitUtil) { bean -&amp;gt;&lt;br /&gt;            bean.scope = &amp;quot;prototype&amp;quot;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What this says is to create a bean with the name &lt;span style="font-style:italic;"&gt;dbunitUtil&lt;/span&gt; of the type com.redpointtech.dbunit.DBUnitUtil and set the scope to prototype.  Because my DBUnitUtil does keep track of some DBUnit artifacts, I decided to require a new instance to avoid any thread synchronization issues.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 3 - Add my Java class DBUnitUtil.java to Grails src&lt;/span&gt;&lt;br /&gt;In the root directory of the Grails plugin application, there is a folder called 'src'.  In that folder there is another called 'java', and in there I placed the com.redpointtech.dbunit.DBUnitUtil.java class.  Since this post is not about the DBUnit part, I am not going to go into the details of that class but it is included in the source distribution at the end of this blog post.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 4 - Add DBUnit jars to the lib dir&lt;/span&gt;&lt;br /&gt;In the root directory of the Grails plugin application, there is a lib folder and in there I placed the dbunit-2.4.4.jar file.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Step 5 - package the plugin&lt;/span&gt;&lt;br /&gt;Because I have not applied for contributor access, I cannot release the plugin so for now I can only package up the plugin and make it available locally.  To package the plugin you use the command from the root of the plugin project:&lt;br /&gt;&lt;br /&gt;grails package-plugin&lt;br /&gt;&lt;br /&gt;This created a file called &lt;span style="font-style:italic;"&gt;gails-dbunit-0.1.zip&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Thats it - I now have a plugin I can use in any grails application to help support integration testing.&lt;br /&gt;&lt;br /&gt;On a side note - Grails supports unit tests and integration tests.  Unit tests are supposed to be very lightweight and will not initialize all of the database infrastructure so you have to create integration tests to test the &lt;br /&gt;&lt;br /&gt;I created another application that I called gormtest and I used many of the Domain classed from the Album/Song/Artist example from the Grails book.&lt;br /&gt;&lt;br /&gt;To use the new plugin you can install a plugin directly from the zip file using the following command:&lt;br /&gt;&lt;br /&gt;grails install-plugin [full path to the gails-dbunit-0.1.zip]&lt;br /&gt;&lt;br /&gt;Doing this makes a Spring available to my Integration tests.  I created an itegration test using the following:&lt;br /&gt;&lt;br /&gt;grails create-integration-test com.redpointtech.gtunes.Album&lt;br /&gt;&lt;br /&gt;This created a file called AlbumTests.groovy in the test/integration/com/redpointtech/gtunes directory.&lt;br /&gt;&lt;br /&gt;An abbreviated version of the AlbumTests.groovy file follows:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;1 package com.redpointtech.gtunes&lt;br /&gt;2 &lt;br /&gt;3 import grails.test.*&lt;br /&gt;4 import com.redpointtech.dbunit.*&lt;br /&gt;5 import javax.sql.DataSource&lt;br /&gt;6 &lt;br /&gt;7 class AlbumTests extends GrailsUnitTestCase {&lt;br /&gt;8     DataSource dataSource&lt;br /&gt;9     DBUnitUtil dbunitUtil&lt;br /&gt;10    &lt;br /&gt;11    &lt;br /&gt;12    protected void setUp() {&lt;br /&gt;13        super.setUp()&lt;br /&gt;14           dbunitUtil.onSetup(dataSource, &amp;quot;./data/user-testdata.xml, ./data/album-testdata.xml&amp;quot;) &lt;br /&gt;15  }&lt;br /&gt;16&lt;br /&gt;17    protected void tearDown() {&lt;br /&gt;18        super.tearDown()&lt;br /&gt;19        dbunitUtil.onTearDown()&lt;br /&gt;20    }&lt;br /&gt;21    &lt;br /&gt;22    void testAlbumFind() {&lt;br /&gt;23        def albums = Album.findAllByTitleLike(&amp;quot;title1%&amp;quot;)&lt;br /&gt;24        assertEquals albums.size, 3&lt;br /&gt;25        albums.each { album -&amp;gt;&lt;br /&gt;26            println &amp;quot;------------------------------------&amp;quot;&lt;br /&gt;27            println &amp;quot;Title: &amp;quot; + album.getTitle()&lt;br /&gt;28            def artist = album.getArtist()&lt;br /&gt;29            println &amp;quot;Artist: &amp;quot; + artist.getName()&lt;br /&gt;30            }&lt;br /&gt;31    }    &lt;br /&gt;32}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On lines 8 and 9, we create two instance variables that Grails will automatically inject the beans into - following the naming convention.  The first is the dataSource used for the test and the second is the DBUnitUtil bean that is provided by the Plugin we just created.&lt;br /&gt;&lt;br /&gt;On line 14, we use the DBUnit plugin bean, to load the database referenced by the dataSource, with the data in the two XML files.  &lt;br /&gt;&lt;br /&gt;On line 19, we use the dbunitUtil bean again to tear down the data used for the test. I know someone is going to ask about the  time it takes to load and unload all of the data for each test and it is a fair concern.  My suggestion is to group as many tests in the single test method as is practical, and since I dont think anyone would really want to create dependencies between their tests you probably do want to start with a fresh data load for the next test.&lt;br /&gt;&lt;br /&gt;On line 23, we can then start to use the GORM API, against the data that was loaded by the DBUnit plugin.&lt;br /&gt;&lt;br /&gt;The last part to take care of is the XML data files.  I placed the data files in the grails-app/conf directory in a subdirectory called &lt;span style="font-style:italic;"&gt;data&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The user-testdata.xml file looks like the following:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;dataset&amp;gt;&lt;br /&gt;    &amp;lt;user id=&amp;quot;1000&amp;quot; version=&amp;quot;1&amp;quot; first_name=&amp;quot;user1_fn&amp;quot; last_name=&amp;quot;user1_ln&amp;quot; user_name=&amp;quot;user1_un&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;user id=&amp;quot;2000&amp;quot; version=&amp;quot;1&amp;quot; first_name=&amp;quot;user2_fn&amp;quot; last_name=&amp;quot;user2_ln&amp;quot; user_name=&amp;quot;user2_un&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;user id=&amp;quot;3000&amp;quot; version=&amp;quot;1&amp;quot; first_name=&amp;quot;user3_fn&amp;quot; last_name=&amp;quot;user3_ln&amp;quot; user_name=&amp;quot;user3_un&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;user id=&amp;quot;4000&amp;quot; version=&amp;quot;1&amp;quot; first_name=&amp;quot;user4_fn&amp;quot; last_name=&amp;quot;user4_ln&amp;quot; user_name=&amp;quot;user4_un&amp;quot; /&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;&amp;lt;/dataset&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is pretty much all there is to creating a simple DBUnit plugin, that leveraged the Java code I already had to pre-populate a test database with data so I could start to get familiar with the GORM api through the integration tests.&lt;br /&gt;&lt;br /&gt;The source code for both the dbunit plugin and the gormtest application can be found here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.theyoungsouls.com//blogs/redpoint/grails/dbunitplugin/dbunit-grails-plugin-0.1.zip"&gt;DBUnit Grails Plugin&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.theyoungsouls.com//blogs/redpoint/grails/dbunitplugin/gormtest-grails-app-0.1.zip"&gt;Gormtest Grails App&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-3916429340811330930?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/3916429340811330930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=3916429340811330930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/3916429340811330930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/3916429340811330930'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/03/creating-grails-plugin-for-dbunit.html' title='Creating a Grails Plugin for DBUnit'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-7247764772090382631</id><published>2009-03-15T13:02:00.009-05:00</published><updated>2009-03-15T13:16:26.715-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>How to create a popup window from an ItemEditor</title><content type='html'>I was recently helping a client that needed to create an item editor that would allow them to update the text field of a data grid, which also rendered an Icon that the user could click to create a comment line.  Clicking the comment Icon would bring up a popup window to edit the comments.  When the popup window was dismissed, the UI should show the ItemEditor in a state to allow the user to complete the editing of the original DataGrid item.&lt;br /&gt;&lt;br /&gt;In their initial implementation they did not use the ItemEditEnd event from the DataGrid, because they noticed that when the popup window was created the ItemEditEnd event would fire and Flex would go through the entire process of ending the editing session.  Clearly not what they wanted.  The client went through a number of 'workarounds' but they always avoided the ItemEditEnd event.  &lt;br /&gt;&lt;br /&gt;I think trying to circumvent the cell editing process is almost always a bad idea that leads to code that will break as new releases of the Flex framework come out, and will certainly confuse developers that have to maintain the code.  So I set off trying to create a simplified example of two options for them, one of which was a popup window.  Since it was sufficiently tricky - I thought there may be others out there that would benefit from this example.&lt;br /&gt;&lt;br /&gt;Below is a working example of what I put together.  In the top DataGrid, I setup the comment editor to NOT use a popup window and instead just toggle between a textinput to edit the cell data, and a textinput to edit the comment line.  Personally I find the popup window awkward to the user experience - but that was the client requirement.  The second DataGrid is a simplified version of the required popup window.  Notice that it only allows for a single line and takes the return key as the single to end editing the comment.&lt;br /&gt;&lt;br /&gt;You can find the code for this example &lt;a href="http://www.theyoungsouls.com/blogs/redpoint/flexexamples/ItemRendererPopupTest-src.zip"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed pluginspage=" http://www.macromedia.com/go/getflashplayer" src="http://www.theyoungsouls.com/blogs/redpoint/flexexamples/ItemRendererPopupTest.swf" width="525" height="450" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-7247764772090382631?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/7247764772090382631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=7247764772090382631' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7247764772090382631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7247764772090382631'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/03/how-to-create-popup-window-from.html' title='How to create a popup window from an ItemEditor'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-7389134781858926001</id><published>2009-02-03T23:55:00.002-06:00</published><updated>2009-03-15T12:42:57.288-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>Flex ItemRenderers - and the case of the random renderering</title><content type='html'>I was reading through the book 'Flex 3 in Action' and I came across what seemed like a simple ItemRenderer example that I thought would be good show some people because it demonstrated what not to do, the visual consequences and then how to fix it.  Except - in my testing it did not fix it.&lt;br /&gt;&lt;br /&gt;The purpose of the blog posting is to highlight the issues and how I ultimately solved it - albeit I don't fully understand yet why it was happening.  That will take a little more time.&lt;br /&gt;&lt;br /&gt;The example was a simple one.  There is a data grid with a data provider of objects and if the object has an email address show a button in the grid that the user can press to send the person an email.  If the object in the dataprovider has no email address do not show the button.&lt;br /&gt;&lt;br /&gt;This example is taken from section 9.2.3, page 190 of Flex 3 In Action.&lt;br /&gt;&lt;br /&gt;Below is a working example from that section.  In the first data grid, the ItemRenderer was incorrectly implemented just as the authors suggest.  That being during creationComplete event we check the data to see if we should render the email button.  This is incorrect, because Flex will reuse ItemRenderers and the creationComplete method should only be called once.&lt;br /&gt;&lt;br /&gt;In the 'correct' version, we look for the dataChange event and then run the logic again to see if we should render the email button.  However, I noticed that if I scrolled the list to the bottom, and then scrolled up via the scroll button one line at a time, the first time Mikey Mouse did not get a button.  For some reason, the creationComplete was called for that ItemRenderer - even though the ItemRenderer that was there had its dataChange event called.  Or at least that is how it appeared.  Why this is happening I am not sure.  However, to fix this problem I changed the creationComplete to call the checkEmail function just like dataChange and enhanced the error checking to make sure we cover the case where the ItemRenderer is created before the data property is set. &lt;br /&gt;&lt;br /&gt;Now in the third data grid, you can scroll to the bottom, and then back up and see that Mikey Mouse can now still receive email...&lt;br /&gt;&lt;br /&gt;Source can be found by clicking &lt;a href="http://www.theyoungsouls.com/blogs/redpoint/flexexamples/flex3inaction-itemrenderer-src.zip"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If anyone knows why the example exercise did not work, please leave a comment.&lt;br /&gt;&lt;br /&gt;&lt;embed pluginspage=" http://www.macromedia.com/go/getflashplayer" src="http://www.theyoungsouls.com/blogs/redpoint/flexexamples/ItemRendererTest1.swf" width="600" height="600" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-7389134781858926001?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/7389134781858926001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=7389134781858926001' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7389134781858926001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7389134781858926001'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/02/flex-itemrenderers-and-case-of-random.html' title='Flex ItemRenderers - and the case of the random renderering'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-1069447837400275611</id><published>2009-01-31T17:21:00.000-06:00</published><updated>2009-01-31T17:45:31.235-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='Hibernate'/><title type='text'>Hibernate DAO using Spring and Java Generics</title><content type='html'>Having created a number of Hibernate DAOs it does not take long to see a pattern emerge which would seem to lend itself to a typed generic DAO.  As any good engineer will do, I first set off to see if someone else had already thought about this.  It is sometimes easier to stand on the shoulders of giants, and I found one.&lt;br /&gt;&lt;br /&gt;The work I am going to present was really inspired by the following blog posting:&lt;br /&gt;&lt;br /&gt;http://www.nileshk.com/node/66&lt;br /&gt;&lt;br /&gt;But I wanted to change the implementation somewhat, and add more methods that made sense to my problem domain.  So what I am going to present is an extension to the above blog posting.  The purpose of this is not to suggest that one implementation is better or worse, they are just different and I actually hope that perhaps my implementation will inspire someone else in their work.&lt;br /&gt;&lt;br /&gt;The AbstractDao interface looks like the following - with nearly every comment removed for clarity.  I hope the method names are suggestive enough:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;package com.redpointtech.dao;&lt;br /&gt;&lt;br /&gt;import java.util.Collection;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * borrowed heavily from: http://www.nileshk.com/node/66&lt;br /&gt; */&lt;br /&gt;public interface AbstractDao &amp;lt;DomainObject, KeyType&amp;gt; {&lt;br /&gt;    &lt;br /&gt;    void update(DomainObject object);&lt;br /&gt;    void refresh(DomainObject object);&lt;br /&gt;    void save(DomainObject object);&lt;br /&gt;    Long saveOrUpdate(DomainObject object);&lt;br /&gt;    void saveAll(Collection&amp;lt;DomainObject&amp;gt; objects);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    DomainObject load(KeyType id);&lt;br /&gt;    List&amp;lt;DomainObject&amp;gt; findAll();&lt;br /&gt;    List&amp;lt;DomainObject&amp;gt; findAllOrderById();&lt;br /&gt;    DomainObject findById(KeyType id);    &lt;br /&gt;    List&amp;lt;DomainObject&amp;gt; findByIds(Collection&amp;lt;KeyType&amp;gt; idList);&lt;br /&gt;    List&amp;lt;DomainObject&amp;gt; findAllOrderByProp(String propertyName, Boolean asc);&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;    int  deleteAll();&lt;br /&gt;    void deleteAll(Collection&amp;lt;DomainObject&amp;gt; objects);&lt;br /&gt;    void delete(DomainObject object);&lt;br /&gt;    void deleteById(KeyType id);&lt;br /&gt;    int  deleteByIds(Collection&amp;lt;KeyType&amp;gt; ids);&lt;br /&gt;&lt;br /&gt;    int count();&lt;br /&gt;    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The Implementation looks as follows:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;package com.redpointtech.dao;&lt;br /&gt;&lt;br /&gt;import static org.springframework.util.CollectionUtils.isEmpty;&lt;br /&gt;&lt;br /&gt;import java.io.Serializable;&lt;br /&gt;import java.lang.reflect.ParameterizedType;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Collection;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import org.hibernate.Criteria;&lt;br /&gt;import org.hibernate.EntityMode;&lt;br /&gt;import org.hibernate.Query;&lt;br /&gt;import org.hibernate.criterion.Order;&lt;br /&gt;import org.hibernate.criterion.Projections;&lt;br /&gt;import org.hibernate.criterion.Restrictions;&lt;br /&gt;import org.hibernate.metadata.ClassMetadata;&lt;br /&gt;import org.springframework.orm.hibernate3.support.HibernateDaoSupport;&lt;br /&gt;import org.springframework.util.Assert;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * &lt;br /&gt; * borrowed heavily from: http://www.nileshk.com/node/66&lt;br /&gt; */&lt;br /&gt;public abstract class AbstractHibernateDaoImpl&amp;lt;T extends Serializable, KeyType extends Serializable&amp;gt;&lt;br /&gt;    extends HibernateDaoSupport implements AbstractDao&amp;lt;T, KeyType&amp;gt;{&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    protected Class&amp;lt;T&amp;gt; domainClass = getDomainClass();&lt;br /&gt;&lt;br /&gt;    public void refresh(T t) {&lt;br /&gt;        getHibernateTemplate().refresh(t);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public T load(KeyType id) {&lt;br /&gt;        return (T) getHibernateTemplate().load(domainClass, id);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public T findById(KeyType id) {&lt;br /&gt;        return (T) getHibernateTemplate().get(domainClass, id);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public List&amp;lt;T&amp;gt; findByIds(Collection&amp;lt;KeyType&amp;gt; idList) {&lt;br /&gt;        Assert.notNull(idList, &amp;quot;idList parameter cannot be null&amp;quot;);&lt;br /&gt;        ClassMetadata cmd = getHibernateTemplate().getSessionFactory().getClassMetadata(domainClass);&lt;br /&gt;        String idProp = cmd.getIdentifierPropertyName();&lt;br /&gt;        &lt;br /&gt;        if( idList.size() &amp;gt; 0 ) {&lt;br /&gt;            Criteria criteria = getHibernateTemplate().getSessionFactory()&lt;br /&gt;                .getCurrentSession().createCriteria(domainClass);&lt;br /&gt;                criteria.add(Restrictions.in(idProp, idList));&lt;br /&gt;            &lt;br /&gt;            return  criteria.list();&lt;br /&gt;        } else {&lt;br /&gt;            return new ArrayList&amp;lt;T&amp;gt;();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public void update(T t) {&lt;br /&gt;        getHibernateTemplate().update(t);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void save(T t) {&lt;br /&gt;        getHibernateTemplate().saveOrUpdate(t);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public Long saveOrUpdate(T t) {&lt;br /&gt;        getHibernateTemplate().saveOrUpdate(t);&lt;br /&gt;        Long id = (Long)getHibernateTemplate().getSessionFactory().getClassMetadata(domainClass).getIdentifier(t, EntityMode.POJO);&lt;br /&gt;        return id;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void saveAll(Collection&amp;lt;T&amp;gt; list) {&lt;br /&gt;        if(!isEmpty(list)) {&lt;br /&gt;            getHibernateTemplate().saveOrUpdateAll(list);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    public void delete(T t) {&lt;br /&gt;        getHibernateTemplate().delete(t);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public List&amp;lt;T&amp;gt; findAll() {&lt;br /&gt;        return (getHibernateTemplate().find(&amp;quot;from &amp;quot; + domainClass.getName()&lt;br /&gt;            + &amp;quot; x&amp;quot;));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public List&amp;lt;T&amp;gt; findAllOrderById() {&lt;br /&gt;        ClassMetadata cmd = getHibernateTemplate().getSessionFactory().getClassMetadata(domainClass);&lt;br /&gt;        String idProp = cmd.getIdentifierPropertyName();&lt;br /&gt;        &lt;br /&gt;        return findAllOrderByProp(idProp,true);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public List&amp;lt;T&amp;gt; findAllOrderByProp(String propertyName, Boolean asc) {&lt;br /&gt;        &lt;br /&gt;        Criteria criteria = getHibernateTemplate().getSessionFactory()&lt;br /&gt;            .getCurrentSession().createCriteria(domainClass);&lt;br /&gt;        if( asc ) {&lt;br /&gt;          criteria.addOrder(Order.asc(propertyName));&lt;br /&gt;        } else {&lt;br /&gt;          criteria.addOrder(Order.desc(propertyName));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        return criteria.list();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;    public void deleteById(KeyType id) {&lt;br /&gt;        Object obj = load(id);&lt;br /&gt;        getHibernateTemplate().delete(obj);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)&lt;br /&gt;    public int deleteByIds(Collection&amp;lt;KeyType&amp;gt; ids) {&lt;br /&gt;      int count = 0;&lt;br /&gt;      &lt;br /&gt;     if(!isEmpty(ids)) {&lt;br /&gt;      &lt;br /&gt;        ClassMetadata cmd = getHibernateTemplate().getSessionFactory().getClassMetadata(domainClass);&lt;br /&gt;          String idProp = cmd.getIdentifierPropertyName();&lt;br /&gt;          &lt;br /&gt;          String hqlDelete = &amp;quot;delete &amp;quot; + domainClass.getName() + &amp;quot; x where x.&amp;quot; + idProp + &amp;quot; in ( :ids )&amp;quot;;&lt;br /&gt;          &lt;br /&gt;          Query deleteQuery = getHibernateTemplate().getSessionFactory().getCurrentSession().createQuery(hqlDelete);&lt;br /&gt;          deleteQuery.setParameterList(&amp;quot;ids&amp;quot;, ids);&lt;br /&gt;          &lt;br /&gt;          count = deleteQuery.executeUpdate();&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;        return count;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void deleteAll(Collection&amp;lt;T&amp;gt; objects) {&lt;br /&gt;    if(!isEmpty(objects)) {&lt;br /&gt;      getHibernateTemplate().deleteAll(objects);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;    public int deleteAll() {&lt;br /&gt;        &lt;br /&gt;        String hqlDelete = &amp;quot;delete &amp;quot; + domainClass.getName();&lt;br /&gt;        Query deleteQuery = getHibernateTemplate().getSessionFactory().getCurrentSession().createQuery(hqlDelete);&lt;br /&gt;&lt;br /&gt;        int count = deleteQuery.executeUpdate();&lt;br /&gt;        return count;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int count() {&lt;br /&gt;      ClassMetadata cmd = getHibernateTemplate().getSessionFactory().getClassMetadata(domainClass);&lt;br /&gt;        String idProp = cmd.getIdentifierPropertyName();&lt;br /&gt;        &lt;br /&gt;        Criteria criteria = getHibernateTemplate().getSessionFactory()&lt;br /&gt;          .getCurrentSession().createCriteria(domainClass);&lt;br /&gt;        criteria.setProjection(Projections.countDistinct(idProp));&lt;br /&gt;        Object countValue = criteria.uniqueResult();&lt;br /&gt;        &lt;br /&gt;        return Integer.parseInt(countValue.toString());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected Class getDomainClass() {&lt;br /&gt;        if (domainClass == null) {&lt;br /&gt;            ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();&lt;br /&gt;            domainClass = (Class) thisType.getActualTypeArguments()[0];&lt;br /&gt;        }&lt;br /&gt;        return domainClass;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I incorporated this into my Redpoint Notes reference project and I will show how that looks for the DAO hierarchy.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NotesDao&lt;/b&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.dao;&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import com.redpointtech.domain.Note;&lt;br /&gt;&lt;br /&gt;public interface NotesDao {&lt;br /&gt;  &lt;br /&gt;  List&amp;lt;Note&amp;gt; getAllNotes();&lt;br /&gt;  &lt;br /&gt;  Long saveOrUpdate(Note note);&lt;br /&gt;  &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;HibernateNotesDao Interface&lt;/b&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.dao;&lt;br /&gt;&lt;br /&gt;import com.redpointtech.domain.Note;&lt;br /&gt;&lt;br /&gt;public interface HibernateNotesDao extends NotesDao,&lt;br /&gt;    AbstractDao&amp;lt;Note, Long&amp;gt; {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;HibernateNotesDaoImpl&lt;/b&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;package com.redpointtech.dao.impl;&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;import org.springframework.stereotype.Repository;&lt;br /&gt;&lt;br /&gt;import com.redpointtech.dao.AbstractHibernateDaoImpl;&lt;br /&gt;import com.redpointtech.dao.HibernateNotesDao;&lt;br /&gt;import com.redpointtech.domain.Note;&lt;br /&gt;&lt;br /&gt;@Repository(&amp;quot;hibernateNotesDao&amp;quot;)&lt;br /&gt;public class HibernateNotesDaoImpl extends AbstractHibernateDaoImpl&amp;lt;Note, Long&amp;gt;&lt;br /&gt;    implements HibernateNotesDao {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public List&amp;lt;Note&amp;gt; getAllNotes() {&lt;br /&gt;    List&amp;lt;Note&amp;gt; notes = this.findAll();&lt;br /&gt;    return notes;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see I wrote virtually no code beyond what the abstract generic implementation gives me - and the getAllNotes is really contrived just to show how you would add a specific DAO method.&lt;br /&gt;&lt;br /&gt;Using this kind of generic Hibernate DAO has saved us a lot of time and I hope you find this useful as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-1069447837400275611?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/1069447837400275611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=1069447837400275611' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/1069447837400275611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/1069447837400275611'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/01/hibernate-dao-using-spring-and-java.html' title='Hibernate DAO using Spring and Java Generics'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-4021826401064577977</id><published>2009-01-25T15:24:00.001-06:00</published><updated>2009-01-25T21:58:07.918-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><category scheme='http://www.blogger.com/atom/ns#' term='BlazeDS'/><title type='text'>Spring Blaze Integration 1.0 M1 with Hibernate</title><content type='html'>I have a reference project that I have been using to stitch the different Spring/Hibernate/Flex/AIR technologies together.&lt;br /&gt;&lt;br /&gt;Well today, I wanted to upgrade to Spring3 and look at the new Spring BlazeDS Integration.  You can find all of the information about the Spring BlazeDS integration &lt;a href="http://blog.springsource.com/2008/12/17/using-spring-blazeds-integration-m1/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This particular project used as Flex 3 front end, communicating to a Tomcat/Spring2.5/SpringJDBC to MySql database.  Today I decided to upgrade the application to use Spring3 and Hibernate 3.3.1 which I did not anticipate being a big project - but I was wrong.  Well ok, it was not a big project but it was bigger than I expected it to be.&lt;br /&gt;&lt;br /&gt;If you following along with the sample application from the Spring/BlazeDS integration it goes really well.  &lt;br /&gt;&lt;br /&gt;However when you go to integrate Hibernate and use the OpenSessionInViewFilter things get a little tricky.&lt;br /&gt;&lt;br /&gt;Conventional Spring wisdom would have us use the ContextLoaderListener to load the Spring context much like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    &amp;lt;context-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;/WEB-INF/classes/main-application-config.xml&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/context-param&amp;gt;&lt;br /&gt;  &lt;br /&gt;    &amp;lt;listener&amp;gt;&lt;br /&gt;        &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;    &amp;lt;/listener&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;However, when I did that the MessageBroker complained that the ServletConfig was null so I decided I would initialize the Spring application context as the Spring BlazeDS Integration suggested.  However - when I did that, the OpenSessionInView Filter complained that the web application context was not initialized.&lt;br /&gt;&lt;br /&gt;So I was between the proverbial rock and a hard place.  &lt;br /&gt;&lt;br /&gt;I spent some time looking through the code to see how I could 'fix' this problem.  Then it occurred to me that perhaps it was not a problem with the code.  Maybe, this could fixed with a different configuration.  The OpenSessionInView filter just needs information about the Hibernate Session, SessionFactory, DataSource, etc.  It does not need to know about the MessageBroker and the MessageBroker does not need the Hibernate information.&lt;br /&gt;&lt;br /&gt;So instead of trying to fix the code, I looked at how to fix my configuration.&lt;br /&gt;&lt;br /&gt;I looked at my application config, and removed all of the elements that were related to Blaze integration and created a separate configuration for the servlet to load.  I now have the ContextLoaderListener initialize part of the application config and the servlet the other part. &lt;br /&gt;&lt;br /&gt;Here is a portion of the web.xml file configuration:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    &amp;lt;context-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;/WEB-INF/classes/main-application-config.xml&amp;lt;/param-value&amp;gt;&lt;br /&gt;    &amp;lt;/context-param&amp;gt;&lt;br /&gt;  &lt;br /&gt;    &amp;lt;listener&amp;gt;&lt;br /&gt;        &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;&lt;br /&gt;    &amp;lt;/listener&amp;gt;&lt;br /&gt;    &lt;br /&gt;   &lt;br /&gt;    &amp;lt;filter&amp;gt;&lt;br /&gt;      &amp;lt;filter-name&amp;gt;hibernate-session&amp;lt;/filter-name&amp;gt;&lt;br /&gt;      &amp;lt;filter-class&amp;gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&amp;lt;/filter-class&amp;gt;&lt;br /&gt;      &amp;lt;init-param&amp;gt;&lt;br /&gt;        &amp;lt;param-name&amp;gt;sessionFactoryBeanName&amp;lt;/param-name&amp;gt;&lt;br /&gt;        &amp;lt;param-value&amp;gt;sessionFactory&amp;lt;/param-value&amp;gt; &lt;br /&gt;      &amp;lt;/init-param&amp;gt;&lt;br /&gt;    &amp;lt;/filter&amp;gt;&lt;br /&gt;    &amp;lt;filter-mapping&amp;gt;&lt;br /&gt;        &amp;lt;filter-name&amp;gt;hibernate-session&amp;lt;/filter-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;    &amp;lt;/filter-mapping&amp;gt;&lt;br /&gt;  &lt;br /&gt;    &amp;lt;servlet&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;redpointnotes&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;         &lt;br /&gt;        &amp;lt;init-param&amp;gt;&lt;br /&gt;          &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;&lt;br /&gt;          &amp;lt;param-value&amp;gt;/WEB-INF/classes/blaze-config.xml&amp;lt;/param-value&amp;gt;&lt;br /&gt;        &amp;lt;/init-param&amp;gt;&lt;br /&gt;           &lt;br /&gt;        &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;    &lt;br /&gt;    &amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;servlet-mapping&amp;gt;&lt;br /&gt;        &amp;lt;servlet-name&amp;gt;redpointnotes&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;        &amp;lt;url-pattern&amp;gt;/spring/*&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;    &amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The blaze-config.xml file looks like the following:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;  &amp;lt;bean id=&amp;quot;mySpringManagedMessageBroker&amp;quot; &lt;br /&gt;    class=&amp;quot;org.springframework.flex.messaging.MessageBrokerFactoryBean&amp;quot; /&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;bean id=&amp;quot;flexMessageBroker&amp;quot; abstract=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;messageBroker&amp;quot; ref=&amp;quot;mySpringManagedMessageBroker&amp;quot; /&amp;gt;&lt;br /&gt;  &amp;lt;/bean&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!-- bean id name is the name that will be exposed to Flex remoting as the destination name --&amp;gt;&lt;br /&gt;  &amp;lt;bean id=&amp;quot;redpointNotesServiceDestination&amp;quot; parent=&amp;quot;flexMessageBroker&amp;quot;&lt;br /&gt;    class=&amp;quot;org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;service&amp;quot; ref=&amp;quot;notesService&amp;quot; /&amp;gt;&lt;br /&gt;  &amp;lt;/bean&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;bean class=&amp;quot;org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping&amp;quot; /&amp;gt;&lt;br /&gt;  &amp;lt;bean class=&amp;quot;org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter&amp;quot; /&amp;gt;  &lt;br /&gt;&lt;br /&gt;  &amp;lt;!-- map request paths at /messagebroker to the BlazeDS MessageBroker --&amp;gt;&lt;br /&gt;  &amp;lt;bean class=&amp;quot;org.springframework.web.servlet.handler.SimpleUrlHandlerMapping&amp;quot;&amp;gt;&lt;br /&gt;    &amp;lt;property name=&amp;quot;mappings&amp;quot;&amp;gt;&lt;br /&gt;      &amp;lt;value&amp;gt;&lt;br /&gt;        /messagebroker/*=mySpringManagedMessageBroker&lt;br /&gt;      &amp;lt;/value&amp;gt;&lt;br /&gt;    &amp;lt;/property&amp;gt;&lt;br /&gt;  &amp;lt;/bean&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!-- dispatches requests mapped to a message broker --&amp;gt;&lt;br /&gt;  &amp;lt;bean class=&amp;quot;org.springframework.flex.messaging.servlet.MessageBrokerHandlerAdapter&amp;quot; /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So by breaking up the configuration I was able to get around this 'chicken-n-egg' problem but I will still look to see if there is a more elegant way to handle this.  If anyone has a better way of dealing with this, please post a comment so we can all benefit.&lt;br /&gt;&lt;br /&gt;I hope this helps save someone some time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-4021826401064577977?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/4021826401064577977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=4021826401064577977' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/4021826401064577977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/4021826401064577977'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/01/spring-blaze-integration-10-m1-with.html' title='Spring Blaze Integration 1.0 M1 with Hibernate'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1798575258168757722.post-7830702364016066588</id><published>2009-01-24T14:13:00.000-06:00</published><updated>2009-01-24T21:15:38.602-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Redpoint'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>Flex Camp Chicago 2009</title><content type='html'>Hi Everyone&lt;br /&gt;&lt;br /&gt;I just got back from Flex Camp Chicago 2009 and I would first like to thank everyone that worked so hard to make this event happen.  It was a very informative camp with a wide range technical perspectives - both from presenters and the people in attendance.&lt;br /&gt;&lt;br /&gt;There was so much covered during those two days, so instead of trying to summarize it all I am going to take certain presentations and topics and blog on those over the next few days. &lt;br /&gt;&lt;br /&gt;The second day Keynote was from &lt;a href="http://www.jamesward.com/blog/" target="_blank"&gt;James Ward&lt;/a&gt;.  He created his 'Top 10 things to like' and Flex.  Here is a summary of that list.  I am also including some audio clips of each of the 10 topics he discussed.  Since some of what he did was actual code, it will be a little hard to follow just the audio but it is still worth the listen.:&lt;br /&gt;&lt;br /&gt;#1 Threads with PixelBender&lt;br /&gt;As you may know - the FlashPlayer is single threaded, at least as far as our applications are concerned, and this therefore makes long running calculations very difficult to do.  With PixelBender, you have the ability to create very lightweight threads of execution.  Now - there are plenty of reasons to not get too excited about this.  First, it is not a robust threading model that those of us in the Java world have come to know and love ( or not love ).  Second, you have to know how to program with the PixelBender language.  What I did find interesting is the number of times threading the Flash Player came up during the conference.  There definitely seems to be mounting pressure for a multithreaded environment capability.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_1.mp3&amp;audio_duration=420" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;#2 Text Layout Framework&lt;br /&gt;This was very cool and I am really looking forward to these new features.  You can find all of the details on the &lt;a href="http://labs.adobe.com/technologies/textlayout/" target="_blank"&gt;Adobe Labs site&lt;/a&gt;, but here is a quick summary.&lt;br /&gt;* Flowing text around columns - including selection.  True multi-column output is now going to be part of the framework. &lt;br /&gt;* Text alpha for fading, etc.  You can fade text in/out with a single font.&lt;br /&gt;* Bidirectional text, vertical text in over 30 writing systems.  Now that is 'International'&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_2.mp3&amp;audio_duration=370" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;#3 Openness&lt;br /&gt;Adobe continues to make more of its platform open which allows developers like us to really embrace and build upon the great work at Adobe.  Currently AMF, Flex SDK, BlazeDS are all examples of their open source.  Adobe recently announced the RTMP spec will be made open allowing for more choices in the streaming media.  Last - but not least - check out bugs.adobe.com.  If you are find a bug check to see if it is in the bug database, and if not submit.  If you do find, please vote for it.  This is our communication channel back to Adobe on what we feel is important to get fixed.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_3.mp3&amp;audio_duration=210" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;#4 Tour de Flex&lt;br /&gt;This one is really awesome! You can take the Tour &lt;a href="http://flex.org/tour" target="_blank"&gt;here&lt;/a&gt; but finish reading the top 10 list before you leave.&lt;br /&gt;If you are fan of the component explorer - you are going to love Tour de Flex.  It is similar to the component explorer except it is an AIR application, and it has much more content.  You can see all of the components, interact with examples, see source code - just like with component explorer, but now the documentation is also integrated in.  In addition to this, components offered by the community will also be available through Tour de Flex.  There is also a great Eclipse plugin that integrates with Tour de Flex using another very cool new technology called Merapi ( thats my second topic for the blog post ).&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_4.mp3&amp;audio_duration=300" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#5 Portable RIAS&lt;br /&gt;What does this mean? I can hear you ask.  We are all now familiar with running Flex applications via a web browser - but have you ever thought about running a Flex application from a PDF document?  For detailed information checkout James Ward's posting on &lt;a href="http://www.jamesward.com/blog/portable-rias-tutorial/" target="_blank"&gt;Portable RIAs&lt;/a&gt;.  James showed a demo of how he took the dashboard application, exported it to PDF and was able to actually run the application from the PDF document.  The PDF was also able to update its data from the server.  PDF Reader 9 and above comes with the flash player embedded which makes all of this possible.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_5.mp3&amp;audio_duration=460" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#6 Flex 4 Gumbo&lt;br /&gt;This is the new version of Flex and the Flex builder.  There are a lot of exciting changes coming and the &lt;a href="http://opensource.adobe.com/wiki/display/flexsdk/Gumbo" target="_blank"&gt;Gumbo SDK&lt;/a&gt; is available now from Adobe Labs.  There are some great resource links on this page and I highly recommend you check them out.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_6.mp3&amp;audio_duration=210" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#7 Rapid Application Development without the Rapids.&lt;br /&gt;In this part of his presentation he talked about the new workflow and wizard capabilities to get applications up and running quickly.  He was able to very quickly get a data driven, synchronized application up and running.  &lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_7.mp3&amp;audio_duration=550" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;#8 AMF&lt;br /&gt;James discussed and showed the Census demo which shows you how much better AMF is to all other protocols to communicate between Flex and the server.  He made an interesting comments as part of an answer to a question.  James commented that he would always use AMF over all other protocols unless there was a good reason not to.  He also showed the group how easy it was to use RemoteObject with a remote server.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_8.mp3&amp;audio_duration=1060" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;#9 RIA Best Practices.&lt;br /&gt;James did not enumerate any particular best practices, but commented on the state of best practices and what RIA developers should consider.  These practices are independent of the RIA technology and he is working with people from the Microsoft and JavaFX team.  They have a site that you can reach &lt;a href="http://www.riapractices.com/wiki/default.aspx?AspxAutoDetectCookieSupport=1" target="_blank"&gt;here called RIA Practices&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_9.mp3&amp;audio_duration=90" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;#10 You&lt;br /&gt;The developer community that maintains the interest level in the technology and all of the developers contributing to the open source movement.&lt;br /&gt;&lt;br /&gt;&lt;embed src= "http://www.odeo.com/flash/audio_player_standard_black.swf" quality="high" width="300" height="52" allowScriptAccess="always" wmode="transparent"  type="application/x-shockwave-flash" flashvars="valid_sample_rate=true&amp;external_url=http://www.theyoungsouls.com/blogs/redpoint/flexcamp2009/JamesWard_10.mp3&amp;audio_duration=40" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt; &lt;br /&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;Thanks so much for checking out my blog and come back often as I will be adding additional entries for other Flex Camp Chicago 2009 topics.   My next blog entry will talk about Merapi which is a project to allow AIR and Java to communicate with one another.  I see some really cool possibilities with this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1798575258168757722-7830702364016066588?l=redpointtech.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://redpointtech.blogspot.com/feeds/7830702364016066588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1798575258168757722&amp;postID=7830702364016066588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7830702364016066588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1798575258168757722/posts/default/7830702364016066588'/><link rel='alternate' type='text/html' href='http://redpointtech.blogspot.com/2009/01/flex-camp-chicago-2009.html' title='Flex Camp Chicago 2009'/><author><name>Patrick Ryan</name><uri>http://www.blogger.com/profile/00370055637063982666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_g6qrdsLdFFc/SYTcH-ucHLI/AAAAAAAAAAM/MLTldvjSJgM/S220/pryan.png'/></author><thr:total>0</thr:total></entry></feed>
