Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Thursday, June 05, 2008

Tapestry with Groovy

While I'm waiting for the vote on Tapestry 5.0.12, I'm starting some work on a more complete demo application. As usual, I'm trying to teach myself a bunch of new things, such as using Ant and Ivy (in place of Maven), and using Groovy for my pages, entities and services.

I'm still having trouble with live class reloading in Tomcat, so I'm staying with Jetty for a bit longer.

The Groovy stuff for pages and such is just fine. My demo application is a simple blogging site (boring stuff, but a domain model everyone understands). I don't have much yet, but my first page lists recents blog postings:

<t:grid source="recentPostings"/>

And the page class is written in Groovy:

package com.nfjs.hls.blog.pages

import org.apache.tapestry5.ioc.annotations.Inject
import org.hibernate.Session

class Index
    Session session

    def getRecentPostings()
        session.createQuery("from Posting order by posted desc").setMaxResults(20).list()        

A few notes; the session gets injected even though the property is not private; Groovy is creating a private instance variable and a getter/setter for the property. That's just perfect.

I also like how succinct the getRecentPostings() method is. In previous apps, I tended to create a DAO service to hide some of the Java Generics ugliness, but that just stops being an issue here. With IDEA, I still get most of my editor support as well.

Tapestry has no knowledge of Groovy; IDEA is compiling the .groovy files to .class files and Tapestry is loading them. That's the beauty of the JVM.

For this simple example, we could write Java code that is nearly as succinct, but going forward I see no reasons why the Groovy code will not be significantly shorter, simpler and more readable than the equivalent Java code.

There's no reason to limit the use of Groovy to the pages and components. Entity classes in Groovy are also nice:

package com.nfjs.hls.blog.entities

import javax.persistence.*
import org.apache.tapestry5.beaneditor.DataType
import org.apache.tapestry5.beaneditor.NonVisual
import org.apache.tapestry5.beaneditor.ReorderProperties
import org.apache.tapestry5.beaneditor.Validate

@ReorderProperties ("title,posted,content")
class Posting
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    Long id

    @ManyToOne (optional = false)
    Blog blog

    @Column (nullable = false)
    @Validate ("required")
    String title;

    @Column (nullable = false)
    @Validate ("required")
    @DataType ("longtext")
    String content

    @Column (nullable = false)
    Date posted

The @Validate annotations are Tapestry-specific and are being applied to the fields (allowing this is a new feature in 5.0.12). Because the getters and setters are generated without line numbers, the order of the properties ends up being a jumble; the @ReorderProperties annotation puts them into a reasonable order. You win some, you lose some.

On the services side of things, Groovy is a big win with Tapestry IOC. I have an AppModule to configure a few things, such as turning off production mode (which turns on full exception reports), and I want to override part of my Hibernate configuration in development mode:

package com.nfjs.hls.blog.services

import org.apache.tapestry5.SymbolConstants
import org.apache.tapestry5.hibernate.HibernateConfigurer
import org.apache.tapestry5.ioc.MappedConfiguration
import org.apache.tapestry5.ioc.OrderedConfiguration
import org.apache.tapestry5.ioc.annotations.Symbol

class AppModule

    def contributeApplicationDefaults(MappedConfiguration configuration)
        configuration.add SymbolConstants.PRODUCTION_MODE, "false"
    def contributeHibernateSessionSource(OrderedConfiguration configuration,

                                         @Symbol ("tapestry.production-mode")
                                         boolean productionMode)
        if (!productionMode)
            configuration.add "DevMode", {conf ->
                conf.setProperty "hibernate.show_sql", "true"
                conf.setProperty "hibernate.format_sql", "true"
                conf.setProperty "hibernate.hbm2ddl.auto", "create"
            } as HibernateConfigurer

The ability to wrap a closure as a simple interface (the kind of callback interface used throughout Tapestry) is very, very useful. The only fly in the ointment is GROOVY-2827, which keeps me from using SymbolConstants.PRODUCTION_MODE with the @Symbol annotation on the productionMode parameter.

I think I can get used to the Groovy syntax; I actually prefer the Groovy closure syntax to the Ruby block syntax though I generally prefer the Ruby approach elsewhere.

I expect to write all of this application in Groovy, and that may ultimately become an overall recommendation. Just us crazy framework authors should be coding in pure Java!


Hazelnut said...

Hi Howard,

It's been nice to see significant T5 progress being made and the arrival of the AjaxFormLoop component that many of us have been looking forward to.

I am a little surprised that there's a vote on the 5.0.12 release though, given how many outstanding bugs there are in Jira. I'm very much a newbie to Tapestry, so I'm not familiar with the development process or anything - I just figured that it might be worth clearing some of the bugs before releasing a new beta. (especially mine of course.. hehe)

I raised one today on the new AjaxFormLoop component by the way, I'm not sure if you've seen it yet. Like many others I'm very keen to see a final 5.0 release, but I know it can't be rushed. Fixing the outstanding bugs is what's going to be needed to get there I think, so I hope that's going to be the focus of 5.0.13 and we'll see the bugs dropping like flies. ;-)

The Groovy stuff looks interesting, I hope it doesn't distract you too much from core T5 development though.


Howard said...

It's been a couple of months since the last dot release. There's still a number of rough edges in T5 but we are getting very close to a release. Getting wider exposure for 5.0.12 will help.

Outside of bug fixes and docs, I don't think there's anything urgent that has to be in 5.0. I'd rather get a useable 5.0 out the door and follow on with 5.1, 5.2, 5.3 in short order. No more big bang releases!

Hazelnut said...

Agreed, and you're right that getting wider exposure to 5.0.12 will assist in ironing out those rough edges, even if bug numbers rise initially. I guess I was just getting nervous about the amount that are not getting squished at the moment. I'll be sure to keep my eye out for any more of the little critters.

You must be pretty excited about the upcoming release given how much time and effort you've invested in T5. I'm excited myself and I'd never heard of Tapestry until 3 months ago... lol.

Jaime said...

I started a project with Tapestry (5.0.11) and Groovy. It's grate to see the improvements for this integration, currently I am having those problems, specially with validator.

On the other hand, the only good groovy plugin I found was from IntelliJ. I prefer eclipse over IntelliJ but eclipse dose not have a good plugin. What I specially hate from IntelliJ is the way it deploys the project each time you compile. It reloads the whole applications. I am the kind of developer who compiles each time that a class is saved, so, if you do this with IntelliJ it is terrible waste of time. I prefer the eclipse way that you just save the file and compilations is done automatic, the Web Container (tomcat in my case) just reloads only if the class that you compiled was loaded by the ClassLoader. Eclipse compiles faster.

Another thing is the SVN support. Again, I think the way Eclipse dose its easier to use than opening another window each time you need to use SVN.

Tapestry + Groovy its a good combination, but Groovy needs better support on different IDEs. It even would be grate a Tapestry + Groovy + GORM, but now Hibernate dose a good job.

Howard said...

I think IntelliJ does use too many modal dialogs but once you get into its rythym, you tend not to notice.

I can't fault its SVN support; seems pretty easy to use, on par with SVN in Eclipse.

In terms of building; IDEA usually does the opposite of what you are describing: only builds when you ask it to. I have things configured to build on frame deactivation, but not re-deploy, which is perfect for T5. As I switch from IDEA to Firefox, my code gets recompiled and the changes are picked up as soon as I click a link. Dive deeper into your Tomcat or Jetty launch configuration, and the Project / Compile preferences.