5

私は Groovy を初めて使用し、そのメタプログラミング機能を調べ始めたばかりです。Bean コンストラクター呼び出しで不足しているプロパティを追加することに行き詰まりました。

FactoryBuilderSupport で使用するクラスで、コンストラクターの呼び出し時にまだ定義および提供されていないプロパティを動的に追加したいと考えています。ここに簡素化されたバージョンがあります:

@Canonical
class MyClass {
    def startDate
    def additionalProperties = [:]

    def void propertyMissing(String name, value) {
        additionalProperties[name] = value
    }
}

ただし、不明なプロパティでクラスを構築すると、プロパティは追加されませんが、MissingPropertyException代わりに次のようになります。

def thing = new MyClass(startDate: DateTime.now(), duration: 1234)

プロパティの期間は存在しませんpropertyMissing。私がグルーヴィーを理解している限り、タプル コンストラクターを呼び出すと、引数のないコンストラクターの呼び出しに続いて、グルーヴィーによって生成されたセッターが呼び出されます。では、なぜ私は を取得するのMissingPropertyExceptionですか?

私は groovy に慣れていないので、基本的な AST または MOP ルールがいくつか欠けている可能性があります。ご協力をお願いいたします。

4

1 に答える 1

1

アノテーションで行っているのと同じように使用@Canonicalして最初のクラスオブジェクトを定義すると、次のコンストラクターが生成されます。defstartDate

@Canonical
class MyClass {
    def startDate
    def additionalProperties = [:]

    def void propertyMissing(String name, value) {
            additionalProperties[name] = value
    }
}

// use reflection to see the constructors
MyClass.class.getConstructors() 

生成されたコンストラクター:

public MyClass() 
public MyClass(java.lang.Object)
public MyClass(java.util.LinkedHashMap)
public MyClass(java.lang.Object,java.lang.Object)

@Canonical ドキュメントでは、次の制限を確認できます。

最初のプロパティのタイプが LinkedHashMap の場合、または単一の Map、AbstractMap、または HashMap プロパティがある場合、Groovy の通常のマップ スタイルの命名規則は使用できません。

が生成されるため、public MyClass(java.util.LinkedHashMap)使用できずtuple-constructor、 が得られMissingPropertyExceptionます。

驚くべきことに、 を使用する代わりに を使用してfirstオブジェクト ( と言うことに注意してください) を定義すると、注釈は を追加せず、呼び出しが機能します。次のコードを参照してください。firsttypedef@Canonicalpublic MyClass(java.util.LinkedHashMap)tuple-constructor

@Canonical
class MyClass {
    java.util.Date startDate
    def additionalProperties = [:]

    def void propertyMissing(String name, value) {
            additionalProperties[name] = value
    }
}
// get the constructors
MyClass.class.getConstructors()
// now your code works
def thing = new MyClass(startDate: new java.util.Date(), duration: 1234)

作成されたコンストラクターは次のとおりです。

public MyClass()
public MyClass(java.util.Date)
public MyClass(java.util.Date,java.lang.Object)

というわけpublic MyClass(java.util.LinkedHashMap)で制限がかからないので問題なくtuple-constructor動作します。

さらに、このソリューションが機能するため、理由について議論することはできません...@Canonicalドキュメントを何度も読みましたが、この動作が説明されている部分が表示されないため、なぜこれが機能するのかわかりません方法、また、いくつかの試行を行いますが、first要素が作成された場合にのみ少し混乱します。defpublic MyClass(java.util.LinkedHashMap)

@Canonical
class MyClass {
    def a
    int c
}
// get the constructors
MyClass.class.getConstructors()

def...として定義された最初のオブジェクト

public MyClass()
public MyClass(java.lang.Object)
public MyClass(java.util.LinkedHashMap) // first def...
public MyClass(java.lang.Object,int)

順序を変更すると、次のようになります。

@Canonical
class MyClass {
    int c
    def a
}
// get the constructors
MyClass.class.getConstructors()

最初は生成されずdefpublic MyClass(java.util.LinkedHashMap)生成されません。

public MyClass() 
public MyClass(int)
public MyClass(int,java.lang.Object)

お役に立てれば、

于 2014-09-29T08:09:11.193 に答える