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

后一种方法更加动态,因为可以在运行时确定要混合的类。有关 Groovy mixins 的更多信息,请参见此处

以我的经验,很多领域类的元编程根本行不通。我不完全知道为什么,但怀疑这是因为这些类已经被 Grails 运行时进行了非常大量的元编程。一般来说,我的方法是

  • 在 Groovy 控制台中尝试在 POGO 上进行元编程
  • 如果可行,请在 Grails 控制台中的非域类上尝试
  • 如果可行,请在 Grails 控制台中的域类上尝试。如果它不起作用,那么它一定是因为它是一个域类(而不是语法问题)。在这一点上,建议尝试找到另一种实现目标的方法。如果这不可能,那么结合使用 Grails 邮件列表和/或 Stackoverflow 和/或 Grails 源代码来尝试让元编程工作。
于 2009-08-13T20:42:51.823 回答
11

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

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

class Person {}

Person.mixin MyMixin

new Person().doStuff()
于 2009-01-22T15:07:19.583 回答
4

我猜你所看到的与其说是一个特性,不如说是一个提议;)Groovy 还不支持以这种方式开箱即用的mixin(如果有的话)。但是有一个 3rd 方库可以用来模拟这种行为:Injecto。并且可以在 1.6 版本的 Groovy(还不是最终版本)中使用 AST-Macros 定义 mixins。

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

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

干杯

于 2009-01-08T20:16:36.893 回答
2

万一这对任何人都有帮助,从上面的@virtualeyes 评论开始,我发现

Person.doStuff()

除非您先调用以下命令,否则失败:

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

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

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

那没有用!

于 2013-08-10T06:21:00.777 回答
1

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

于 2009-01-21T05:26:25.403 回答
0

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

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

使用特质!

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

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

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

new B().printAnything() 

试试看!

于 2018-10-22T22:37:24.423 回答