Recursive evaluation of ant properties in Flaka
Facts - Other software technologies
Wednesday, 29 June 2011 20:39

In Flaka library version 1.02.02 (flaka version 1.2.2) one can recursively edit properties inside ant (version 1.8.2) projects:

<property name="my" value="xx"/>
<property name="xx_yy" value="123"/>
<fl:properties>
  my_property=#{${xx}_yy}
</fl:properties>
<echo>My property = ${my_property} ; output will be 'My property = 123'</echo>

This works still when using an ant property containing a single dot in its name:

<property name="my" value="xx"/>
<property name="xx.yy" value="123"/>
<fl:properties>
  my_property=#{${xx}.yy}
</fl:properties>
<echo>My property = ${my_property} ; output will be 'My property = 123'</echo>

But it does not work using an ant property containing multiple dots in its name:

<property name="my" value="xx"/>
<property name="xx.yy.zz" value="123"/>
<fl:properties>
  my_property=#{${my}.yy.zz}; null
</fl:properties>
<echo>My property = ${my_property} ; output will be 'My property = '</echo>

In that case one could still rely on task propertycopy in external library ant-contrib or even better on a macro:

<macrodef name="propertycopy">
  <attribute name="name"/>
  <attribute name="from"/>
  <sequential>
    <property name="@{name}" value="${@{from}}"/>
  </sequential>
</macrodef>
 
<property name="my" value="xx"/>
<property name="xx.yy.zz" value="123"/>
<propertycopy name="my_property" from="${my}.yy.zz"/>
<echo>My property = ${my_property} ; output will be 'My property = 123'</echo>

But I wrote an email on this issue to the author of the Flaka library. He immediately responded:

Rather a problem of explaining EL syntax properly I' afraid.

The base problem is that character dot (.) has no operational meaning in properties and is used to make "readable" identifiers. This is different from EL where character dot means "lookup something".

In EL, "xx.yy.zz" translates into lookup('zz', lookup('yy',xx)), i.e. get EL-property 'yy' on EL-object 'xx', then get EL-property 'zz' on the returned object.

So all works fine as long as a property name is dot-less. Otherwise disasters strikes. Have a look at your modified example:

<project xmlns:fl="antlib:it.haefelinger.flaka">
 
 <property name="my" value="xx"/>
 <property name="xx.yy.zz" value="123"/>
 <fl:properties>
   my.property = #{ property['${my}.yy.zz'] }
   my.my       = #{ my }
 </fl:properties>
 
 <echo>
   My property = ${my.property} ; expected output 'My property = 123'
   My my       = ${my.my}  ; expected output 'My my = xx'
 </echo>
 
</project>

If you run this, you should get

$ ant -lib ~/lib/flaka/ant-flaka.jar
Buildfile: /exp/flaka-issue/build.xml
      [echo]
      [echo]     My property = 123 ; expected output 'My property = 123'
      [echo]     My my         = xx  ; expected output 'My my = xx'
      [echo]
 
BUILD SUCCESSFUL
Total time: 0 seconds

Agreed, it's a confusing issue cause we got used to use '.' in properties. However, one could have implemented something like 'if there is no object named "xx" then try property "xx.yy.zz" instead. That's all fine but what if there is an EL object named "xx" and properties starting with "xx." ..??

So my conclusion is that when using ant properties containing dots in an EL enabled context one has to use the the construct property['..'] in order to "escape" the dots:

my.property = #{ property['${my}.yy.zz'] }

Instead of

my.property = #{ ${my}.yy.zz }

After solving this issue I wondered how to call flaka code from Groovy code within an ant target. This comes down to calling something within an antlib namespace from Groovy. See below, I haven't tested it:

import groovy.xml.NamespaceBuilder
def flaka = NamespaceBuilder.newInstance(ant, 'antlib:it.haefelinger.flaka')
flaka.properties(){ "my.property = #{ property['" +properties.get("my") +".yy.zz']}" }