TSSJS was a great conference this year. Neal Ford, well-known author and ThoughtWorker, initiated the conference by delivering an inspiring keynote address discussing dynamic languages, DSLs (Domain-specific languages), and their role in the evolution of software development. Matt Raible blogged about the presentation and you can find a brief summary here. Polyglot programming became a theme of the conference with Ted Neward delivering yet another inspiring keynote encouraging developers to create their own language.

Building on this inspiration, Scott Davis discussed taking the Groovy Red Pill. Well, you would be happy to know I have taken the Red Pill, but of course with a Seam twist. I have been working on a time-tracking application (for my company’s internal use) utilizing Seam and Groovy that I will release as a freely available example. Groovy and Seam integration will be discussed in-depth in JBoss Seam 2E, but let’s look at the Groovy way to initialize a Timesheet:

@Entity
class GroovyTimesheet
{
  @Id @GeneratedValue
  Long id;

  @OneToMany
  @JoinColumn(name="TIMESHEET_ID")
  List<GroovyTimeEntry> entries = new ArrayList<GroovyTimeEntry>();

  GroovyTimesheet(PayPeriod payPeriod, int month, int year)
  {
    (payPeriod.getStartDate(month, year)..
      payPeriod.getEndDate(month, year)).each
    {
      entries << new GroovyTimeEntry(hours:0, date:it);
    }
  }

  // ... ...
}

So what is going on here? Essentially we define a range of dates that are iterated over. The PayPeriod is a fairly simple enum that determines the start and end dates of a pay period. By specifying (startDate..endDate) we define a range. Groovy understands the meaning of a range of dates allowing us to express this in a very concise manner (try expressing this in Java and you’ll get the picture). In addition, we use the each operation on this range. The each operation allows us to define a closure that executes as Groovy loops through our range of dates a day at a time. This allows us to initialize each GroovyTimeEntry instance for the pay period.

You will also note use of the << operator (or the leftShift operator). This operator is defined for a List allowing us to add elements to the list through this syntactic sugar. The GroovyTimeEntry instance is initialized using the default construction approach. By default, named constructor parameters can be specified in any order to initialize an object instance. If you define a constructor this is no longer provided by default. Finally, you will notice the use of the keyword it in the closure we defined for the each operation. The keyword it provides the value of the current element in the iteration. So in our instance, as we loop through the date range, each date will be provided iteratively in the range.

@Entity
class GroovyTimeEntry {
  @Id @GeneratedValue
  Long id;

  BigDecimal hours;
  Date date;
}

Wow, is that all the code? Looks pretty nice doesn’t it. As mentioned, the default constructor allows us to specify named parameters. In addition, getters and setters are automatically provided for each of our attributes.

You’ve probably noticed the use of JPA annotations here. This is perfectly legal and your groovy class will be a JPA entity. The same is true for Seam components annotated with @Name. So how does this work? Groovy classes are compiled to Java bytecode under the covers so JEE and Seam features are fully available to your Groovy classes at runtime. Simply use the groovyc compiler that can be accessed here or include the groovyc Ant task into your build. This will be covered in-depth in JBoss Seam 2E.

So what if we want to add GroovyTimeEntry instances to the GroovyTimesheet instance programmatically? The following code implements this:

@Entity
class GroovyTimesheet
{
  // ... ...

  void leftShift(GroovyTimeEntry entry)
  {
    entries << entry;
  }

  // ... ...
}

As mentioned, the leftShift operator is provided by Groovy and can be overloaded within your custom implementations. By defining a custom leftShift implementation we are now able to add a GroovyTimeEntry instance through the following:

// ... ...
timesheet << new GroovyTimeEntry(new Date());
// ... ...

Operator overloading isn’t limited to the leftShift operation. We can also overload other operators such as +:

// ... ...
BigDecimal plus(GroovyTimeEntry entry)
{
  this.hours + entry.hours;
}
// ... ...

This allows us to add the hours of two GroovyTimeEntry instances using the simple + operator. Notice that a return is not specified. This is optional as the last line is assumed to be a return statement.

As mentioned, a complete time-tracking application will be provided that not only demonstrates Groovy entities but also Groovy Seam components. In addition, the time-tracking application will make use of the ExpandoMetaClass to extend final Java classes at run-time! The code for the application is in development and will be made available through Google code. Also, stay tuned for JBoss Seam 2E which will provide the intimate details of Groovy and Seam integration. So take the Red Pill and use the meta-programming features of Groovy in your own Seam applications!