使用groovy类别添加动态属性

时间:2013-02-26 16:53:01

标签: groovy metaclass

扩展this blog post,我试图使用一个类别来创建一个简单的DSL,用于javax.measure(JSR-275)类(类似于TimeCategory的时间间隔)

但是,我不想为每种可能的方法(getMeter,getMilliMeter,getKelvin,getSecond等)添加样板代码。我认为覆盖getProperty(String)方法会起作用,但唉,看起来直接访问属性时不会使用类别中定义的getProperty方法。

以下是一些简化的代码来演示:     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
}

假设其他动态向运行时对象添加属性的方法(例如Expando,子类化GroovyInterceptible,mixins和其他元类操作)是不可行的,我真的不需要手动编写getter for每个可能的单位和SI前缀组合。显然还有其他方法可以为测量创建DSL,但我仍然想了解为什么这种方法不起作用。

有人可以解释为什么该类别的getProperty方法不会覆盖.propertyName用法吗?我显然遗漏了在运行时使用元类解析属性名称的重要事项。

3 个答案:

答案 0 :(得分:4)

我不知道为什么getProperty不适用于类别。但是你可以在它们上定义一个基本相同的get方法(我认为)。这有效:

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

use (LengthCategory) {
    println 3.m   // 3 m
    println 3.'m' // 3 m
}

答案 1 :(得分:0)

据我所知,你实际上不能使用Category来扩展具有完整(即可读和可写)属性的Integers - 仅使用方法。

您可以使用属性的方法版本,使用只读属性扩展Integer。您甚至可以通过包含set方法使其可写。但是,似乎没有办法存储除静态变量之外传递的值,最终会影响所有整数。

示例:

$ cat catprop
#!/usr/local/bin/groovy

@Category(Integer)
class CatInteger {
  private static String str = "default"
  public static String setN(Integer i, String _str) { str = _str }
  public static String getN(Integer i) { return str }
}

use (CatInteger) {
  3.n = "333a"
  println "3.n is " + 3.n

  3.n = "333b"
  println "3.n is " + 3.n

  4.n = "444"
  println "4.n is " + 4.n
  println "3.n is " + 3.n
}
$ catprop
3.n is 333a
3.n is 333b
4.n is 444
3.n is 444
$

请注意,在最后一行3.n返回“444”,因为存储的字段是静态的。我想可以使用私有HashMap并为每个访问过的Integer存储一个值,但这太难看了。

另一种可能性是使用MetaClass接口的getProperty()和setProperty()。但是,我没有调查过,所以我不知道它是否会起作用(只是一个想法)。

答案 2 :(得分:0)

很好的答案,但不确定,如果你现在还想使用JSR-275 JSR-363是最终的?; - )