Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use groovy categories to add dynamic properties

Expanding on this blog post, I am trying to use a category to create a simple DSL for use with the javax.measure (JSR-275) classes (similar to TimeCategory for time intervals)

However, I do not want to add boilerplate code for each of the possible available methods (getMeter, getMilliMeter, getKelvin, getSecond etc.). I thought overriding the getProperty(String) method would work, but alas, it looks like the getProperty method defined in the category is not used when accessing the property directly.

Here is some simplified code to demonstrate: import javax.measure.quantity.Length; import javax.measure.unit.Unit; import javax.measure.Measure;

@Category(Number)
class LengthCategory {      
    public Measure<BigDecimal, Length> getProperty(String unit){
        return Measure.valueOf(this,Unit.valueOf(unit));
    }
}

use(LengthCategory){
    println 3.getProperty("m")  // this works
    println 3.m                 // this reports a non-exisiting property
    prinlln 3.'m'               // as does this
}

Assuming other methods of dynamically adding properties to a runtime object (e.g. Expando, subclassing GroovyInterceptible, mixins and other metaclass manipulations) is not viable and I would really rather not have to manually code getters for every possible unit and SI prefix combination. There are obviously other ways to go about creating a DSL for measurements, but I would still like to understand why this method would not work.

Could someone explain why the getProperty method of the category does not override .propertyName usage? I am obviously missing something important about the resolution of property names using the metaclass during runtime.

like image 641
RudolphEst Avatar asked Oct 04 '22 21:10

RudolphEst


1 Answers

I don't know why getProperty doesn't work on categories. But you can define a get method on them that does basically the same (i think). This works:

@Category(Number)
class LengthCategory {      
    def get(String unit) {
        "$this $unit"
    }
}

use (LengthCategory) {
    println 3.m   // 3 m
    println 3.'m' // 3 m
}
like image 103
epidemian Avatar answered Oct 10 '22 01:10

epidemian