10

Groovy/Grails アプリでクラスをミックスインしようとしています。 docsで定義されている構文を使用していますが、エラーが発生し続けます。

次のようなドメインクラスがあります。

class Person {
  mixin(ImagesMixin)

  // ...
}

正常にコンパイルされますが、何らかの理由で動作しません。ImagesMixin を含むファイルは、私の/src/groovy/ディレクトリにあります。

Groovy バージョン 1.5.7 および 1.6-RC1 を使用して試してみましたが、うまくいきませんでした。私が間違っていることを誰かが知っていますか?

スタックトレース:

2008-12-30 17:58:25.258::WARN:  Failed startup of context org.mortbay.jetty.webapp.WebAppContext@562791{/FinalTransmission,/home/kuccello/Development/workspaces/lifeforce/FinalTransmission/web-app}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.ExceptionInInitializerError
    at java.security.AccessController.doPrivileged(Native Method)
    at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy:67)
    at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy)
    at Init_groovy$_run_closure6.doCall(Init_groovy:131)
    at RunApp_groovy$_run_closure2.doCall(RunApp_groovy:66)
    at RunApp_groovy$_run_closure2.doCall(RunApp_groovy)
    at RunApp_groovy$_run_closure1.doCall(RunApp_groovy:57)
    at RunApp_groovy$_run_closure1.doCall(RunApp_groovy)
    at gant.Gant.dispatch(Gant.groovy:271)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.processTargets(Gant.groovy:436)
    at gant.Gant.processArgs(Gant.groovy:372)
Caused by: java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at Episode.class$(Episode.groovy)
    at Episode.<clinit>(Episode.groovy)
    ... 13 more
Caused by: groovy.lang.MissingMethodException: No signature of method: static Person.mixin() is applicable for argument types: (java.lang.Class) values: {class ImagesMixin}
    at Broadcast.<clinit>(MyClass.groovy:17)
    ... 17 more
2008-12-30 17:58:25.259::WARN:  Nested in org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.ExceptionInInitializerError:
groovy.lang.MissingMethodException: No signature of method: Person.mixin() is applicable for argument types: (java.lang.Class) values: {class ImagesMixin}
    at Broadcast.<clinit>(Person.groovy:17)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at Episode.class$(BelongsToMyClass.groovy)
    at Episode.<clinit>(BelongsToMyClass.groovy)
    at java.security.AccessController.doPrivileged(Native Method)
    at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy:67)
    at RunApp_groovy$_run_closure2_closure7.doCall(RunApp_groovy)
    at Init_groovy$_run_closure6.doCall(Init_groovy:131)
    at RunApp_groovy$_run_closure2.doCall(RunApp_groovy:66)
    at RunApp_groovy$_run_closure2.doCall(RunApp_groovy)
    at RunApp_groovy$_run_closure1.doCall(RunApp_groovy:57)
    at RunApp_groovy$_run_closure1.doCall(RunApp_groovy)
    at gant.Gant.dispatch(Gant.groovy:271)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.processTargets(Gant.groovy:436)
    at gant.Gant.processArgs(Gant.groovy:372)
2008-12-30 17:58:25.271::INFO:  Started SelectChannelConnector@0.0.0.0:8080
4

7 に答える 7

12

Groovy 1.6 以降、アノテーションを使用して、コンパイル時に mixin をクラスに適用できます。

@Mixin(ImagesMixin)
class Person {
}

または、次のように実行時に mixin を適用できます。

def myMixin = ImagesMixin
Person.mixin myMixin

後者のアプローチは、実行時に mixin するクラスを決定できるため、より動的です。Groovy mixins の詳細については、こちらを参照してください。

私の経験では、ドメイン クラスの多くのメタプログラミングは単純に機能しません。正確な理由はわかりませんが、これらのクラスが Grails ランタイムによってすでに非常に高度にメタプログラミングされていることが原因であると思われます。一般的に、私のアプローチは

  • Groovy コンソールで POGO のメタプログラミングを試す
  • それが機能する場合は、Grails コンソールの非ドメイン クラスで試してください。
  • それが機能する場合は、Grails コンソールのドメイン クラスで試してください。動作しない場合は、(構文の問題ではなく) ドメイン クラスであることが原因であるに違いありません。この時点で、目標を達成するための別の方法を試してみることをお勧めします。それが不可能な場合は、Grails メーリング リストおよび/または Stackoverflow および/または Grails ソース コードを組み合わせて使用​​し、メタプログラミングが機能するようにしてください。
于 2009-08-13T20:42:51.823 に答える
4

あなたが見たのは、機能というよりはむしろ提案だと思います;) Groovy は、この方法ですぐに使用できる mixin をまだサポートしていません (もしあったとしても)。しかし、そのような動作をエミュレートするために使用できるサードパーティのライブラリがあります: Injecto。また、ミックスインは、Groovy の 1.6 バージョン (まだ最終版ではありません) で AST-Macros を使用して定義できます。

実際の groovy プロジェクトからドキュメントを読んでいるのか、それとも GroovyJSR プロジェクト (むしろ提案が収集される場所) からドキュメントを読んでいるのかを常に確認する必要があります。

もう 1 つの方法は、metaClasses を変更することによって、単純な古い MOP を使用して Groovy クラスに動作を注入することです。

乾杯

于 2009-01-08T20:16:36.893 に答える
1

参考までに: 現在、Grails には「埋め込み」ドメインのようなものがありますが、問題があります。これは、あるドメインを別のドメインの一部として論理的に含めることができ、そのフィールドをすべて 1 つの DB テーブルで物理的に発生させることができる場所です。たとえば、住所/都市/州/郵便番号など、複数のテーブルに同じフィールドのサブセットが表示されていることがわかった場合は、StreetAddress ドメインを定義して埋め込むことができます。現在の問題の 1 つは、Grails がフィールドを他のテーブルに埋め込むだけでなく、依然として street_address テーブルを作成することです (トリックをしない限り)。これに対して保留中のパッチが提出されているようです。

于 2009-01-21T05:26:25.403 に答える
0

特性を使おう!

mixin のサポートを削除した理由は、traits のほうが優れているからです。それらは基本的に実装されている抽象クラスです。複数使用して部分クラスとして運用することができます。

trait A {
    void printSomething() {
        println "foobar"
    }
}

class B implements A {
    void printAnything() {
        printSomething()
    }
}

new B().printAnything() 

やってみて!

于 2018-10-22T22:37:24.423 に答える
0

Grails ドメイン オブジェクトは、すでに大量にメタプログラミングされています。グルーヴィーな mixin の代わりに以下を試してください:

@grails.util.Mixin(ImagesMixin)
    class Person {
}
于 2014-09-12T19:03:57.797 に答える