Using Groovy Closures as Scala Functions

I have a Scala trait for persistence and transaction management (which I will blog about in more detail later). The trait looks like:

trait DomainManager {
  def get[E](id: Long)(implicit m: ClassManifest[E]): Option[E]

  def find[E](namedQuery: String, params: Map[String, Any] = null): Option[E]

  //...more methods

  def withTransaction[R](f: (TransactionStatus) => R,
            readOnly: Boolean = false,
            propagationBehavior: PropagationBehavior = PropagationRequired): R
}

Let’s take a look at withTransaction() specifically. It is called like:

val result = domainManager.withTransaction { txStatus =>
  // Access database here
}

If your application is written in Scala or Java it is sometimes handy to have certain pieces of it written in Groovy, to be able to easily change a class and reload it without restarting the application. Your Groovy code will be able to call any of your Java classes, but what about your Scala classes? For example, what if we want to call withTransaction() on DomainManager? How do we deal with the f parameter? And what about the default parameter values?

Groovy and Scala both have the concept of functions as first class objects. In Groovy they are called closures and they are implemented by the class groovy.lang.Closure. In Scala they are called functions and they are implemented by the traits scala.Function0, scala.Function1, ... scala.FunctionN, where N is the number of parameters to the function.

In withTransaction() the type of f is Function1[TransactionStatus, R].  It is a function that takes one parameter of type TransactionStatus and returns a generic R.   

Through Groovy magic closures can be coerced to arbitrary interfaces. For example, I wrapped the withTransaction() method in Groovy like this:

    def withTransaction(Closure closure) {
        domainManager.withTransaction(closure as Function1<TransactionStatus, Object>,
             false, PropagationRequired)
    }

Here the closure parameter is coerced (using the Groovy as coercion operator) to a Scala Function1[TransactionStatus, _] which is the proper type after the generic parameter R is erased.

You cannot use Scala’s default parameter values in Groovy or Java so the last two parameters (readOnly and propagationBehavior) need to be passed explicitly.

Now I can call my Groovy withTransaction() with a closure like:

  def result = withTransaction { txStatus ->
    // Access database here
  }

The same technique can be used to call Scala collection methods like List.map() with Groovy closures.

Templating XML data with Velocity

Velocity is an easy-to-use templating system for the JVM. It’s commonly used to code templates for web pages and email. To use Velocity you pass it a template (a string) and a context, which is a map of Javabeans and collections of Javabeans. The template is coded using the Velocity template language. Here is an example of a template (taken from the Velocity User Guide):

Hello $customer.Name!
<table>
#foreach( $mud in $mudsOnSpecial )
   #if ( $customer.hasPurchased($mud) )
      <tr>
        <td>
          $flogger.promo( $mud )
        </td>
      </tr>
   #end
#end
</table>

What if some of your data is not in Javabean form, but is free form XML (free form meaning you don’t have any control over what the structure is going to be)?

Static languages like Scala and Java are pretty limited for dealing with free form XML. You can parse it into a DOM-like tree or parse it using a SAX-like streaming parser. Then to make the data available to Velocity you would write a Velocity-compatible adapter for the chosen XML API.

Groovy has really nice XML handling capabilities. You can parse XML and then use the results using regular Groovy code, not ugly DOM walking. For example, given this XML:

    <records>
      <car name='HSV Maloo' make='Holden' year='2006>
        <country>Australia</country>
        <record type='speed'>Production Pickup Truck with speed of 271kph</record>
      </car>
      <car name='P50' make='Peel' year='1962'>
        <country>Isle of Man</country>
        <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg</record>
      </car>
      <car name='Royale' make='Bugatti' year='1931'>
        <country>France</country>
        <record type='price'>Most Valuable Car at $15 million</record>
      </car>
    </records>

You can parse and use it like this in Groovy:

def records = new XmlSlurper().parseText(xml)

def allRecords = records.car
assert 3 == allRecords.size()
def allNodes = records.depthFirst().collect{ it }
assert 10 == allNodes.size()
def firstRecord = records.car[0]
assert 'car' == firstRecord.name()
assert 'Holden' == firstRecord.@make.text()
assert 'Australia' == firstRecord.country.text()
def carsWith_e_InMake = 
  records.car.findAll{ it.@make.text().contains('e') }

Using the Groovy API you can write a Velocity adapter for free form XML that exposes most of the power of the native Groovy language features. The Groovy API is just another set of classes that you can use in any JVM application. You can use the API without using the Groovy language itself.

Here is the adapter code in Scala. It wraps Groovy GNodes and GNodeLists with objects that are compatible with Velocity:

import groovy.util.{XmlParser, Node => GNode, NodeList => GNodeList}

object GNodeWrapper
  def xmlToGNode(xml: String) = 
    GNodeWrapper(new XmlParser().parseText(xml))

  def wrapGNodes(n: Any): AnyRef = n match {
    case list: GNodeList => GNodeListWrapper(list)
    case node: GNode => GNodeWrapper(node)
    case x @ _ => x.asInstanceOf[AnyRef]
  }
}
import GNodeWrapper._

case class GNodeWrapper(node: GNode) {
  def get(key: String) = {
    val gnode = node.get(key)
    gnode match {
      case list: GNodeList if list.size == 1 =>
        val n = list.get(0).asInstanceOf[GNode]
        if (n.children.size == 1) {
          n.children.get(0) match {
            case _: GNode => wrapGNodes(n)
            case x @ _ => x
          }
        } else {
          wrapGNodes(n)
        }
      case x @ _ => wrapGNodes(x)
    }
  }

  override def toString: String = node.text
}

case class GNodeListWrapper(nodeList: GNodeList) {
  def get(key: String) = wrapGNodes(nodeList.getAt(key))

  def get(index: Int) = wrapGNodes(nodeList.get(index))

  def size = nodeList.size

  def isEmpty = nodeList.isEmpty

  def iterator = GNodeListIterator(nodeList.iterator)

  override def toString: String = {
    if (nodeList.size == 0) ""
    else
      nodeList.get(0) match {
        case node: GNode => node.text
        case x @ _ => x.toString
      }
  }
}

case class GNodeListIterator(iter: java.util.Iterator[_]) 
      extends java.util.Iterator[AnyRef] {
  def hasNext = iter.hasNext

  def next = wrapGNodes(iter.next)

  def remove() = iter.remove()
}

That’s not much code, especially compared to what the Java/DOM equivalent would be.

Using the adapter looks like:

  // xml is a string containing the sample XML from above
  val contextData =
      Map("title" -> "test title",
          "content" -> "test content",
          "meta" -> GNodeWrapper.xmlToGNode(xml))

  // Renders template and contextData to stringWriter
  velocityEngine.evaluate(new VelocityContext(contextData.asJava), 
                            stringWriter, "example", template)
  

So a template that looks like this:

title=$title
content=$content
country=$meta.records.car[0].country
year=$meta.records.car[2].get('@year')
numcars=$meta.records.car.size()
names=#foreach($c in $meta.records.car)$c.get('@name') #end

Would render like this:

title=test title
content=test content
country=Australia 
year=1931
numcars=3
names=HSV Maloo P50 Royale

The same technique could be used to render free form XML in another templating system like JSP.