Freitag, 8. Juni 2012

Groovy Closures and Annotation Parameters

Since Groovy 1.8 there is support to have a closure as a parameter in annotations. A nice example how to use this feature is the GContracts project, a groovy design by contract framework, which use closure annotation parameters, to define pre and post conditions of a method.

The support of closures in annotations provides a simple way to have much more dynamic in annotations. This is cool and provides new areas where you now could use annotations. Here a simple example how a closure as annotation parameter could be used to group properties.

import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
@Retention(RetentionPolicy.RUNTIME)
@interface Parameter {
Class group()
}
class Group {
final String name
Group(String name){
this.name = name
}
String toString() {
name
}
}
class Data {
def nameGroup = new Group('names')
@Parameter(group={nameGroup})
String lastname
@Parameter(group={nameGroup})
String firstname
def addressGroup = new Group('address')
@Parameter(group={addressGroup})
String street
@Parameter(group={addressGroup})
String location
}
def data = new Data()
data.properties.each {property ->
Data.class.declaredFields.find { field ->
if(field.name == property.key &&
Parameter in field.declaredAnnotations*.annotationType()) {
def parameter = field.getAnnotation(Parameter)
def groupClosure = parameter.group().newInstance(data, data)
def group = groupClosure()
println "Property with name " + property.key +
" is in group " + group
}
}
}

More details about closures in annotation see the groovy 1.8 release notes.

Links:

Dienstag, 5. Juni 2012

Crazy Scala Combinator Parser

Updates
  • 2012-06-?? Add Chris Hodapp version to the post.
  • 2012-06-23 Fix word is now in the second sample no method anymore its a val
Create my first parser with the Scala combinator library. I really like the concept to have simple way to compose simple parsers via high-level functions to a complex parser. But I think the syntax for the internal Scala parser DSL is a little bit crazy. I’m not sure why the method names in Scala always must be as short as possible e.g. rep. For me this makes the source of my simple parser really crazy. Here my first simple key value parser to show how the source of Scala parser looks like.

import scala.util.parsing.combinator.RegexParsers
import scala.collection.immutable.Map
import scala.util.parsing.combinator.PackratParsers
/**
* Simple parser for a key value string like:
* key01 = Value01 key02=value02 key03 =value03 key04= value04
*
* The parser does not support whitespace in key or values.
*/
object KeyValueParser extends RegexParsers {
val emptyMap = Map[String, String]()
def keyValues = rep(keyValue) ^^ {
_.foldLeft(emptyMap)((map , pair) => map ++ Map(pair._1 -> pair._2))
}
def keyValue = key ~ value ^^ {
case key ~ value => (key, value)
}
def key = value ~ eq ^^ {
case key ~ eq => key.toString
}
def value = whitespace ~ word ~ whitespace ^^ {
case _ ~ word ~ _ => word.toString
}
def eq = "=".r
def word = "\\w+".r
def whitespace = "\\s*".r
/**
* Parse a key value text into a Map[String, String].
*/
def parse(input: String) = parseAll(keyValues, input) match {
case Success(result,_) => result
case failure : NoSuccess => throw new Exception(failure.msg)
}
}

The concept behind the Scala combinator parsers are great, try it and you will learn a lot about how to create a parser in functional language. But I don’t understand why always the shortest and cryptic methods names are used in Scala. This type of naming makes the source hard to read and understand and it makes the Scala source so crazy. But when you know the cryptic names it makes a lot of fun to write such crazy Scala source.

Try it more details about regex parsers please see the Scala doc. The demo parser is not perfect and I’m not a Scala professional, if there are any comments feel free write me how to make it better.

A better Scala version of the parser by Chris Hodapp here:
import scala.util.parsing.combinator.RegexParsers
/**
* Simple parser for a key value string like:
* key01 = Value01 key02=value02 key03 =value03 key04= value04
*
* The parser does not support whitespace in key or values.
*/
object KeyValueParser extends RegexParsers {
def map = rep(mapping) ^^ {_.toMap}
def mapping = word ~ "=" ~ word ^^ {
case key ~ _ ~ value => key -> value
}
val word = "\\w+".r
/**
* Parse a key value text into a Map[String, String].
*/
def parse(input: String) = parseAll(map, input) match {
case Success(result,_) => result
case failure : NoSuccess => throw new Exception(failure.msg)
}
}
Links

Groovy Declared Fields Filter Synthetic

Groovy generates some "synthetic" field to a class, that means the reflection method getDeclaredFields returns more fields than fields which are declared in the Groovy source of a class. To filter the "synthetic" fields the Groovy grep method could be used e.g. "anyClass. declaredFields.grep { !it.synthetic }".

import org.junit.Test
class DeclaredFieldsTest
{
static {
Class.metaClass.getNonSyntheticFields = { ->
delegate.declaredFields.grep { !it.synthetic }
}
}
class Data {
public String name
public int count
static def field(name) { Data.class.getField(name) }
}
@Test void getDeclaredFields() {
def expectedFields = [Data.field('name'), Data.field('count')]
assert expectedFields == Data.class.nonSyntheticFields
}
}
Links