Chapter 10. Groovy集成

JBoss Seam的一个特性就是具有RAD(快速应用开发)能力。虽然动态语言与RAD并非同一个意思,但它却是该领域内的一个十分有趣的工具。 直到最近,选择一种动态语言就必须选择完全不同的开发平台(一个带有一系列API和运行环境的开发平台,如果你不想再使用旧的Java API, 这可能是一种幸运,因为你可能不得不被迫使用平台提供的私有API)。 Groovy 打破了这个约束,它是构建在Java虚拟机之上的动态语言。

现在,JBoss Seam通过静态语言和动态语言的无缝集成把动态语言世界和Java EE世界结合起来。 JBoss Seam让开发人员在任务中使用最佳的工具,而不需要关心上下文切换。 编写一个动态Seam组件和编写普通的Seam组件没什么两样,你使用相同的注释、相同的API,所有的一切都是相同的。

10.1. Groovy简介

Groovy是一个基于Java虚拟机的敏捷动态语言,它融合了从Python,Ruby和Smalltalk等语言中的诸多特性。Groovy的强大体现在两个方面:

  • Groovy支持Java语法:Java代码就是Groovy代码,使学习曲线非常平滑,即学习的难度变得非常低。

  • Groovy对象就是Java对象,Groovy类就是Java类:Groovy无缝集成所有已经存在的Java对象和类库。

TODO: 再写一个Groovy语法的快速入门

10.2. 用Groovy编写Seam应用

这个没有什么可多说的,Groovy对象就是Java对象,你可以使用Groovy编写任何Seam组件或者Java类并部署它们。 你也可以在一个应用中混合使用Groovy和Java类。

10.2.1. 编写Groovy组件

你可能已经注意到,Seam大量的使用注解(annotation)。要想Groovy支持注解必须确保其版本在1.1 Beta1以上。 下面是在Seam应用中使用Groovy代码的例子。

10.2.1.1. 实体

    @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本身就支持(getter/setter)方法特性,所以你不用显示的编写冗长的getter和setter方法:在前面的例子中, Hotel类可以通过 <code>hotel.getCity()</code> 这样的语法被Java访问到,getter和setter方法是在Groovy编译时生成的。 这样的语法让实体代码变得非常简洁。

Groovy1.1 Beta1暂时还不支持泛型(Generics)。一个负面影响是实体关系没有内置的类型信息。 这就必须适当的使用 @*ToMany 注解来代替简单的范型定义,就像 <code>Collection<Entity></code>。 出于同样的原因,你也不能从非常有用的 Chapter 11, Seam应用程序框架 中受益。好消息是Groovy1.1正式版将支持范型(Groovy1.1 Beta2正在编写中)。

10.2.1.2. Seam组件

使用Groovy编写Seam组件与使用Java没有什么区别:使用注解将类标记为Seam组件。

@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透明地集成了Groovy。你可以在有seam-gen支持的项目中编写Groovy代码而不需要任何附加支持。 当你编写一个Groovy实体,只需要把 .groovy 文件放在 src/model 目录中即可。 同样的如果编写一个action,只要把 .groovy 文件放在 src/action 目录中就可以了。

10.3. 部署

部署Groovy类与部署Java类非常相像。(令人惊讶的是,不需要编写或者遵循某个3个字母的规范以支持多国语言组件框架)。

JBoss Seam拥有超越标准部署的能力,就是在开发时重新部署JavaBean Seam组件类而不必重启应用程序,这在开发/测试周期中节省了很多时间。 在 .groovy 文件被部署时,Seam对GroovyBean Seam 组件也提供了同样的热部署支持。

10.3.1. 部署Groovy代码

Groovy类就 Java类,和Java类有着同样的字节码。 部署一个Groovy实体、Groovy Session Bean或者Groovy Seam组件,编译步骤是不可缺少的。一个通用的方法是使用 groovyc Ant任务。 一旦编译,Groovy类和Java类不再有区别,应用服务器将它与Java类同样对待。这让Groovy与Java类无缝集成起来。

10.3.2. 开发时部署本地.groovy文件

JBoss Seam本身支持 .groovy 文件(不用编译)的增量热部署(必须是开发模式)。这让编辑/测试周期非常短。 为了设置.groovy部署,请按照 Section 2.7, “Seam与增量热部署” 进行配置,然后部署你的Groovy代码(.groovy文件)到 WEB-INF/dev 目录下。 不需要重启应用程序,GroovyBean组件将被增量启用(当然运行应用程序的服务器也不必重启)。

本地的.groovy文件的部署和其他的Seam热部署有同样的局限:

  • 组件必须是JavaBean或GroovyBean。不能是EJB3 Bean

  • 实体不能热部署

  • 被热部署的组件对部署在 WEB-INF/dev 以外的任何类都是不可见的

  • 必须用Seam Debug模式

10.3.3. seam-gen

Seam-gen透明地支持Groovy文件的部署和编译。包括本地 .groovy 文件在开发模式(未编译的)下的部署。 如果你构建了一个WAR类型的seam-gen项目,在 src/action 目录下的Java和Groovy类会自动参与增量热部署。 如果你在生产模式下,Groovy文件会在部署之前被编译。

你将在 examples/groovybooking 目录下的Booking Demo中找到一个支持增量热部署的完全用Groovy写的例子。