Chapter 10. Groovy integration

One aspect of JBoss Seam is its RAD (Rapid Application Development) capability. While not synonymous with RAD, one interesting tool in this space is dynamic languages. Until recently, choosing a dynamic language was required choosing a completely different development platform (a development platform with a set of APIs and a runtime so great that you would no longer want to use you old legacy Java [sic] APIs anymore, which would be lucky because you would be forced to use those proprietary APIs anyway). Dynamic languages built on top of the Java Virtual Machine, and Groovy in particular broke this approach in silos.

JBoss Seam now unites the dynamic language world with the Java EE world by seamlessly integrating both static and dynamic languages. JBoss Seam lets the application developer use the best tool for the task, without context switching. Writing dynamic Seam components is exactly like writing regular Seam components. You use the same annotations, the same APIs, the same everything.

10.1. Groovy introduction

Groovy is an agile dynamic language based on the Java language but with additional features inspired by Python, Ruby and Smalltalk. The strengths of Groovy are twofold:

  • Java syntax is supported in Groovy: Java code is Groovy code, making the learning curve very smooth

  • Groovy objects are Java objects, and Groovy classes are Java classes: Groovy integrates smoothly with existing Java libraries and frameworks.

TODO: write a quick overview of the Groovy syntax add-on

10.2. Writing Seam applications in Groovy

There is not much to say about it. Since a Groovy object is a Java object, you can virtually write any Seam component, or any class for what it worth, in Groovy and deploy it. You can also mix Groovy classes and Java classes in the same application.

10.2.1. Writing Groovy components

As you should have noticed by now, Seam uses annotations heavily. Be sure to use Groovy 1.1 Beta1 or above for annotation support. Here are some example of groovy code used in a Seam application.

10.2.1.1. Entity

    @Entity
    @Name("hotel")
    class Hotel implements Serializable
    {
        @Id @GeneratedValue
        Long id

        @Length(max=50) @NotNull
        String name

        @Length(max=100) @NotNull
        String address

        @Length(max=40) @NotNull
        String city

        @Length(min=2, max=10) @NotNull
        String state

        @Length(min=4, max=6) @NotNull
        String zip

        @Length(min=2, max=40) @NotNull
        String country

        @Column(precision=6, scale=2)
        BigDecimal price

        @Override
        String toString()
        {
            return "Hotel(${name},${address},${city},${zip})"
        }
    }

Groovy natively support the notion of properties (getter/setter), so there is no need to explicitly write verbose getters and setters: in the previous example, the hotel class can be accessed from Java as hotel.getCity(), the getters and setters being generated by the Groovy compiler. This type of syntactic sugar makes the entity code very concise.

Some temporary gotchas: Groovy 1.1 Beta1 does not (yet) support generics. One negative effect of this is that entity relationships have no built-in type information. It is necessary to use the targetEntity attribute of the appropriate @*ToMany annotation instead of simply using a generic type definition like Collection<Entity>. For the same reason, you won't be able to benefit from the very useful Chapter 11, The Seam Application Framework yet. The good news is that support for generics is targeted for Groovy 1.1 (Groovy 1.1 Beta2 at the time of writing).

10.2.1.2. Seam component

Writing Seam components in Groovy is in no way different than in Java: annotations are used to mark the class as a Seam component.

@Scope(ScopeType.SESSION)
@Name("bookingList")
class BookingListAction implements Serializable
{
    @In EntityManager em
    @In User user
    @DataModel List<Booking> bookings
    @DataModelSelection Booking booking
    @Logger Log log

    @Factory public void getBookings()
    {
        bookings = em.createQuery('''
                select b from Booking b
                where b.user.username = :username
                order by b.checkinDate''')
            .setParameter("username", user.username)
            .getResultList()
    }
    
    public void cancel()
    {
        log.info("Cancel booking: #{bookingList.booking.id} for #{user.username}")
        Booking cancelled = em.find(Booking.class, booking.id)
        if (cancelled != null) em.remove( cancelled )
        getBookings()
        FacesMessages.instance().add("Booking cancelled for confirmation number #{bookingList.booking.id}", new Object[0])
    }
}

10.2.2. seam-gen

Seam gen has a transparent integration with Groovy. You can write Groovy code in seam-gen backed projects without any additional infrastructure requirement. When writing a Groovy entity, simply place your .groovy files in src/model. Unsurprisingly, when writing an action, simply place your .groovy files in src/action.

10.3. Deployment

Deploying Groovy classes is very much like deploying Java classes (surprisingly, no need to write nor comply with a 3-letter composite specification to support a multi-language component framework).

Beyond standard deployments, JBoss Seam has the ability, at development time, to redeploy JavaBeans Seam component classes without having to restart the application, saving a lot of time in the development / test cycle. The same support is provided for GroovyBeans Seam components when the .groovy files are deployed.

10.3.1. Deploying Groovy code

A Groovy class is a Java class, with a bytecode representation just like a Java class. To deploy, a Groovy entity, a Groovy Session bean or a Groovy Seam component, a compilation step is necessary. A common approach is to use the groovyc ant task. Once compiles, a Groovy class is in no way different than a Java class and the application server will treat them equally. Note that this allow a seamless mix of Groovy and Java code.

10.3.2. Native .groovy file deployment at development time

JBoss Seam natively supports the deployment of .groovy files (ie without compilation) in incremental hotdeployment mode (development only). This enables a very fast edit/test cycle. To set up .groovy deployments, follow the configuration at Section 2.7, “Seam and incremental hot deployment” and deploy your Groovy code (.groovy files) into the WEB-INF/dev directory. The GroovyBean components will be picked up incrementally with no need to restart the application (and obviously not the application server either).

Be aware that the native .groovy file deployment suffers the same limitations as the regular Seam hotdeployment:

  • The components must be JavaBeans or GroovyBeans. They cannot be EJB3 bean

  • Entities cannot be hotdeployed

  • The hot-deployable components will not be visible to any classes deployed outside of WEB-INF/dev

  • Seam debug mode must be enabled

10.3.3. seam-gen

Seam-gen transparently supports Groovy files deployment and compilation. This includes the native .groovy file deployment in development mode (compilation-less). If you create a seam-gen project of type WAR, Java and Groovy classes in src/action will automatically be candidate for the incremental hot deployment. If you are in production mode, the Groovy files will simply be compiled before deployment.

You will find a live example of the Booking demo written completely in Groovy and supporting incremental hot deployment in examples/groovybooking.