Tuesday, January 26, 2010

My First Spring Roo App (two months later)

Getting Started with Spring Roo


When I started working with Roo I think they were on RC 2 and now we are on the full-fledged Release 1.0.0, and I noticed that a lot of the tutorials that got me through those early days are a little outdated since a few common commands and generated output have changed over the past two months. I thought since I borrowed so heavily from the ROOsters before me (thanks BTW, Ben Alex and Stefan Schmidt) I would return the favor and talk about my experience a bit. I haven't gotten around to writing my own step-by step guide, but at least I can tell you more about why I chose Roo and pass along the things I have learned along the way.


I don't remember when I first learned about Spring Roo, but right from the start I was impressed. I cut my Spring teeth working on a few fairly large and complicated Spring webapps for about a year before I met Roo. I did the Springsource training, drank the koolaid; I honestly like working with Spring and I feel at home working in Java, but I did miss the fun and seemingly fast-paced development on the Rails projects from my past. Roo promised to bring back the fun and help to make a lot of the routine work of writing Java code disappear.


I had a little side project that started up in November of 2009; the idea was basically a really simple CRUD app. Three domain objects, some security, done. We all know how requirements do tend to change and multiply (especially when you bring a nice-looking and complete webapp as a demo to the first meeting, thanks to Roo), but this project is under control and I am still using Roo to add functionality (like email sending) and to manage the simple domain objects and their controllers and views.


Gotchas


Oh man, have I fallen into a few holes on my way to getting this app off the ground. Some of them turned out to be ROO bugs (I was working with the release candidates, after all) and others were just boneheaded mistakes on my part. In hopes of helping you avoid the same traps here is my list of gotchas and tips for working in Roo. I'll update these as I get a chance, but here are some of my recent lessons learned:


  • If you push in Roo on your domain object so that all of the entity management code is laying around and love to collect all of your imports under something like javax.persistence.* make sure you have an explicit import for javax.persistence.EntityManager. I usually set my minimum pretty low, so that if I optimize imports (ctrl + shift + o in eclipse/STS) then it will use a * instead of listing imports individually if I have more than 10 or so from the same package. That is normally fine, but causes serious problems for your little Roo app. It will yell at you for not returning the right type on your entityManager() method.
  • I am using some security on my manager methods and I went to write a test and I wasn't getting the results I expected. It was saying something about "can't parse expression" referring to the Spring EL expression that is used in the PreAuthorize annotation on my manager method. Well, it turns out I was using the wrong kind of authentication token to fake someone being logged in for my tests. Here is the real way to do it:


    I call this from my test:

    private void addResearcherToSecurityContext(Researcher researcher, boolean admin) {
         Collection authorities = researcher.getAuthorities();
         if (admin) {
             authorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
         }
         TestingAuthenticationToken authentication = new TestingAuthenticationToken(researcher, researcher.getPassword(), authorities.toArray(new GrantedAuthority[authorities.size()]));
         SecurityContextHolder.getContext().setAuthentication(authentication);
    }
    

    and put this in my test application context:
    <bean class="org.springframework.security.authentication.TestingAuthenticationProvider" id="testAuthenticationProvider" />
    

    and put this in my test application security context:
    <authentication-manager alias="authenticationManager">
    <authentication-provider  ref="testAuthenticationProvider" />
    </authentication-manager> 
    

    Simple, huh? It really is. You should know that my Researcher object extends UserDetails and that is what I use for authentication. Now I can write methods where I try to update someone else's account or do admin-y things as a non-admin and make sure that I get an access denied exception and all my data is safe.


  • This is more of a spring/hibernate thing than a Roo gotcha, but I'm going to put it here anyway because it just happened to me again... If you have a manager or, in this case, a test, and all of the methods are transactional. Don't annotate each method with @Transactional because inevitably you are going forget one time and then sit there running your test over and over wondering why it is saying "org.hibernate.SessionException: Session is closed!". You can stick the @Transactional on your class and then you are all set, no matter how many methods you add.
  • Don't forget: the forums and jira are your friends. There is also a seemingly constantly growing list of Roo links and resources on the forum