openxava / documentación / Groovy

Groovy es un lenguaje ágil y dinámico para la plataforma Java. A partir de OpenXava 4m6 puedes escribr el código de tu aplicación usando Groovy en vez de Java. Incluso puedes combinar ambos lenguajes en la misma aplicación.

Configurar Eclipse

La forma más fácil de trabajar con Groovy en OpenXava es usando el plugin de Groovy para Eclipse. Sigue estas instruccionesdel sitio de Groovy para instalar el plugin en Eclipse. Si estás usando una versión de OpenXava anterior a v5.0 ve a Preferences > Groovy > Compiler y escoge Groovy Compiler 1.8.
Has de dar la naturaleza Groovy a tu proyecto OpenXava: pulsa en el botón de la derecha de tu proyecto, y escoge Configure > Convert to Groovy project. Los proyectos OpenXava creados desde v4m6 hasta la v5.9.1 tienen la naturaleza Groovy por defecto.
A partir de ahora, podrás añadir clases Groovy a tu proyecto, o convertir algunas de tus clases Java en clases groovy, y simplemente funcionará. Cuando pulses Ctrl-B las clases .groovy se compilarán en .class automaticamente.

Desde la línea de órdenes

Si trabajas desde la línea de órdenes, en vez de usar Eclipse, añade la nueva tarea ant compilar al build.xml de tu proyecto:
<!--
Compila todos los .java y .groovy
No es necesario llamarla si trabajas desde Eclipse
-->
<target name="compilar">
  <ant antfile="../OpenXava/build.xml" target="compile"/>
</target>
Y acuerdate de llamarla antes de llamar a otra tarea ant:
$ ant compilar desplegarWar
La tarea ant compilar se incluye por defecto en los proyecto nuevos.

Algún código de ejemplo

Puedes escribir las entidades JPA con Groovy:
package org.openxava.test.model;
 
import javax.persistence.*
 
import org.openxava.annotations.*
import org.openxava.calculators.*
import org.openxava.jpa.*
 
@Entity
@Table(name="TOrder")
@View(members="""
    year, number, date;
    customer;
    details;
    amount;
    remarks
    """
)
 
class Order extends Identifiable {
 
    @Column(length=4)
    @DefaultValueCalculator(CurrentYearCalculator.class)
    int year
 
    @Column(length=6)
    int number
 
    @Required
    @DefaultValueCalculator(CurrentDateCalculator.class)
    Date date
 
    @ManyToOne(fetch=FetchType.LAZY, optional=false)
    @ReferenceView("Simplest")
    Customer customer
 
    @OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
    @ListProperties("product.number, product.description, quantity, product.unitPrice, amount")
    Collection<OrderDetail> details = new ArrayList<OrderDetail>()
 
    @Stereotype("MEMO")
    String remarks
 
    @Stereotype("MONEY")
    BigDecimal getAmount() {
        BigDecimal result = 0
        details.each { OrderDetail detail ->
            result += detail.amount
        }
        return result
    }
 
    @PrePersist
    void calculateNumber() throws Exception {
        Query query = XPersistence.getManager()
            .createQuery("select max(o.number) from Order o " +
                    "where o.year = :year")
        query.setParameter("year", year)
        Integer lastNumber = (Integer) query.getSingleResult()
        this.number = lastNumber == null?1:lastNumber + 1
    }
 
}
 
O las acciones:
package org.openxava.test.actions
 
import org.openxava.actions.*
 
class ChangeYearConditionAction extends TabBaseAction {
 
    int year;
 
    void execute() throws Exception {
        tab.setConditionValue("year", year)
    }
 
}
Incluso las pruebas JUnit:
package org.openxava.test.tests
 
import javax.persistence.*
 
import org.openxava.tests.*
import org.openxava.util.*
 
import com.gargoylesoftware.htmlunit.html.*
 
import static org.openxava.jpa.XPersistence.*
 
class OrderTest extends ModuleTestBase {
 
    OrderTest(String testName) {
        super(testName, "Order")
    }
 
    void testCalculatedPropertiesFromCollection_generatedValueOnPersistRefreshedInView()
        throws Exception
    {
        String nextNumber = getNextNumber()
        execute("CRUD.new")
        assertValue("number", "")
        setValue("customer.number", "1")
        assertValue("customer.name", "Javi")
        assertCollectionRowCount("details", 0)
        execute("Collection.new", "viewObject=xava_view_details")
        setValue("product.number", "1")
        assertValue("product.description", "MULTAS DE TRAFICO")
        assertValue("product.unitPrice", "11.00")
        setValue("quantity", "10")
        assertValue("amount", "110.00")
        execute("Collection.save")
        assertNoErrors()
        assertCollectionRowCount("details", 1)
        assertValue("amount", "110.00")
        assertValue("number", nextNumber)
        execute("CRUD.delete")
        assertNoErrors()
    }
 
    void testDoubleClickOnlyInsertsACollectionElement() throws Exception {
        execute("CRUD.new")
        setValue("customer.number", "1")
        assertCollectionRowCount("details", 0)
        execute("Collection.new", "viewObject=xava_view_details")
        setValue("product.number", "1")
        setValue("quantity", "10")
        HtmlElement action = getForm().getElementById(decorateId("Collection.save"))
 
        action.click() // Not dblClick(), it does not reproduce the problem
        action.click()
        Thread.sleep(3000)
 
        assertNoErrors()
        assertCollectionRowCount("details", 1)
 
        execute("CRUD.delete")
        assertNoErrors()
    }
 
    private String getNextNumber() throws Exception {
        Query query = getManager().
            createQuery(
                "select max(o.number) from Order o where o.year = :year")
        query.setParameter("year", Dates.getYear(new Date()))
        Integer lastNumber = (Integer) query.getSingleResult()
        if (lastNumber == null) lastNumber = 0
        return Integer.toString(lastNumber + 1)
    }
 
}

Ojo con las anotaciones anidadas

La mayoría de la sintaxis de Java es compatible con Groovy. Sin embargo, hay un pequeño detalle de la sintaxis de Groovy que hemos de tener en cuenta cuando usamos anotaciones anidadas: hemos de usar [] en vez de {}, como sigue:
@Views([ // Usa [ en vez de {
    @View(members=""" // Usa """ para cadenas multilínea
        edificio [
            nombre, funcion;
            direccion
        ]
    """),
    @View(name="Simple", members="nombre")
]) // Usa ] en vez de }
Fíjate como usamos @Views([ ... ]) en lugar de @Views({ ... }). Fíjate también que podemos usar """ para cadenas multilínea.
Para más detalles sobre la sintaxis de Groovy lee Groovy style and language feature guidelines for Java developers.