Groovy 混合?

发布于 2024-07-11 15:30:36 字数 3761 浏览 7 评论 0原文

我正在尝试在 Groovy/Grails 应用程序中混合一个类,并且我正在使用 文档中定义的语法,但我不断收到错误。

我有一个如下所示的域类:

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 [email protected]:8080

I'm trying to mix-in a class in my Groovy/Grails app, and I'm using the syntax defined in the docs, but I keep getting an error.

I have a domain class that looks like this:

class Person {
  mixin(ImagesMixin)

  // ...
}

It compiles fine, but for some reason it won't work. The file containing ImagesMixin is located in my /src/groovy/ directory.

I've tried it using Groovy versions 1.5.7 and 1.6-RC1 without any luck. Does anyone know what I'm doing wrong?

stacktrace:

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 [email protected]:8080

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

听风吹 2024-07-18 15:30:36

从 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 源代码来尝试使元编程正常工作。

Since Groovy 1.6 you can either apply a mixin at compile-time to a class using an annotation

@Mixin(ImagesMixin)
class Person {
}

Or you can apply the mixin at runtime like this:

def myMixin = ImagesMixin
Person.mixin myMixin

The latter approach is more dynamic as the class to mixin can be determined at runtime. Further information about Groovy mixins is available here.

In my experience, a lot of meta-programming of domain classes simply doesn't work. I don't exactly know why, but suspect it's due to the fact these classes are already very heavily meta-programmed by the Grails runtime. In general my approach is

  • Try the meta-programming on a POGO in the Groovy console
  • If that works, try it on a non-domain class in the Grails console
  • If that works, try it on a domain class in the Grails console. If it doesn't work, then it must be because it's a domain class (rather than a problem with the syntax). At this point it's advisable to try and find another way of accomplishing your goal. If that's not possible, then use a combination of the Grails mailing list and/or Stackoverflow and/or the Grails source code to try and get the meta-programming working.
银河中√捞星星 2024-07-18 15:30:36

我认为您没有使用正确的 mixin 语法。 尝试这个:

class MyMixin {
    static doStuff(Person) {
        'stuff was done'
    }
}

class Person {}

Person.mixin MyMixin

new Person().doStuff()

I don't think you are using the proper mixin syntax. Try this:

class MyMixin {
    static doStuff(Person) {
        'stuff was done'
    }
}

class Person {}

Person.mixin MyMixin

new Person().doStuff()
暖风昔人 2024-07-18 15:30:36

我想您所看到的与其说是一个提案,不如说是一个功能;)Groovy 还不支持以这种方式开箱即用的混合(如果有的话)。 但是有一个第 3 方库可以用来模拟这种行为:Injecto。 mixin 可以使用 Groovy 1.6 版本(尚未最终版本)中的 AST-Macros 来定义。

您应该始终检查您正在阅读的文档是来自真正的 groovy 项目还是来自 GroovyJSR 项目(这是一个收集提案的地方)。

另一种方法是使用普通的 MOP 通过修改元类将行为注入到 Groovy 类中。

干杯

I guess what you've seen there is rather a proposal than a feature ;) Groovy does not support mixins out of the box in this way yet (if ever). But there is a 3rd party lib that can be used to emulate such a behavour: Injecto. And mixins can be defined using AST-Macros in the 1.6 version of Groovy (which is not final yet).

You should always check if your're reading the docs from the real groovy project or from the GroovyJSR project (which is rather a place where proposals are collected).

Another way is to use plain-old MOP to inject behaviour into groovy classes by modifying metaClasses.

Cheers

〆一缕阳光ご 2024-07-18 15:30:36

如果这对任何人有帮助,根据上面的 @virtualeyes 评论,我发现

Person.doStuff()

除非您先调用以下内容,否则会失败:

new Person().doStuff()
Person.doStuff()

之后,类上的静态方法似乎确实有效(对我来说,使用 Grails 2.2.4)我想这与初始化类或其他东西有关,但我尝试过:

Person.metaClass.initialize()
Person.doStuff()

但这不起作用!

In case this helps anyone, Following on from @virtualeyes comment above, I've found that

Person.doStuff()

fails unless you call the following first:

new Person().doStuff()
Person.doStuff()

after which, the static method on the class does seem to work (for me, using Grails 2.2.4) I guess it's to do with initialising the class, or something, but I tried:

Person.metaClass.initialize()
Person.doStuff()

and that didn't work!

泅人 2024-07-18 15:30:36

仅供参考:Grails 中现在有“嵌入”域之类的东西,但它有问题。 在这里,您可以在逻辑上将一个域包含为另一个域的一部分,并使其字段全部物理地出现在一个数据库表中。 例如,如果您发现多个表中出现相同的字段子集(例如街道地址/城市/州/邮政编码),则可以定义 StreetAddress 域并将其嵌入。 当前的问题之一是,Grails 除了将其字段嵌入到其他表中之外,仍然会创建一个 street_address 表(除非你耍花招)。 似乎有已提交的补丁正在等待处理。

FYI: There is such a thing as "embedded" domains in Grails now, but it has problems. This is where you can logically include one domain as part of another and have its fields all occur physically in the one DB table. For example, if you find that you have the same subset of fields appearing in multiple tables, like street address/city/state/zip, you could define a StreetAddress domain and embed it. One of the current problems is that Grails will still create a street_address table in addition to embedding its fields in the other tables (unless you play tricks). There are submitted patches pending for this, it seems.

岁月打碎记忆 2024-07-18 15:30:36

Grails 域对象已经经过大量元编程。
尝试使用常规的 mixin 来代替:

@grails.util.Mixin(ImagesMixin)
    class Person {
}

Grails domain objects are already heavily meta-programmed.
Instead of the groovy mixin try:

@grails.util.Mixin(ImagesMixin)
    class Person {
}
↙厌世 2024-07-18 15:30:36

使用特质!

Traits 是他们取消对 mixins 支持的原因,因为那样更好。 它们基本上是已实现的抽象类。 允许您使用多个并将它们作为部分类进行操作。

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

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

new B().printAnything() 

试试看!

Use Traits!

Traits are the reason they removed support for mixins, because that are just better. They're basically abstract classes that are implemented. Allowing you to use multiple and operate them as partial classes.

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

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

new B().printAnything() 

Try it out!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文