2009-01-08 56 views
10

我想在我的Groovy/Grails應用程序中混用一個類,並且使用the syntax defined in the docs,但是我一直收到錯誤。Groovy Mixins?

我有一個域類,看起來像這樣:

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 [email protected]{/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 
+0

在開始編碼mixin之前,請確保考慮性能影響。 – user339047 2012-02-27 22:41:05

回答

4

我猜你見過什麼就有什麼,而不是功能的建議;)Groovy的不支持混入了這樣的盒子,但(如果有的話)。但是有一個第三方庫可以用來模擬這種行爲:Injecto。並且可以使用1.6版本的Groovy中的AST宏來定義mixin(這還不是最終的)。

您應該經常檢查您是從真正的groovy項目還是從GroovyJSR項目(這是收集提案的地方)閱讀文檔。

另一種方法是使用普通的MOP通過修改元類將行爲注入到groovy類中。

乾杯

1

FYI:有這樣的事,作爲在Grails的「嵌入式」域現在,但它有問題。這是您可以在邏輯上將一個域作爲另一個域的一部分包含在其中並使其字段全部物理出現在一個數據庫表中的位置。例如,如果您發現在多個表中出現相同的字段子集(例如街道地址/城市/州/郵編),則可以定義一個StreetAddress域並將其嵌入。目前的問題之一是Grails仍然會創建一個street_address表,除了將其字段嵌入到其他表中(除非您玩技巧)。似乎有提交的補丁正在等待這個。

11

我不認爲你使用正確的mixin語法。試試這個:

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

class Person {} 

Person.mixin MyMixin 

new Person().doStuff()
+0

應該`doStuff()`真的是靜態的嗎? – Armand 2011-03-29 16:20:39

+0

是的,它必須是。 – 2011-04-21 16:39:43

12

由於Groovy 1.6中,你可以在編譯時使用註釋

@Mixin(ImagesMixin) 
class Person { 
} 

應用混入到一個類或者你可以在運行時應用混入這樣的:

def myMixin = ImagesMixin 
Person.mixin myMixin 

後一種方法更加動態,因爲mixin類可以在運行時確定。有關Groovy mixins的更多信息,請訪問here

根據我的經驗,很多領域類的元編程根本行不通。我不完全知道爲什麼,但懷疑這是由於這些類已經被Grails運行時重編程了。一般我的做法是

  • 試試元編程在POGO在Groovy的控制檯
  • 如果這樣的作品,嘗試在Grails的非域類控制檯
  • 如果這樣的作品,嘗試它在Grails控制檯中的域類上。如果它不起作用,那麼它一定是因爲它是一個域類(而不是語法上的問題)。在這一點上,建議嘗試找到實現目標的另一種方式。如果這是不可能的,那麼使用Grails郵件列表和/或#1和/或Grails的源代碼,以嘗試並獲得元編程工作的組合。
2

在這種情況下,任何人幫助,從@virtualeyes上述評論繼,我發現,除非你叫

Person.doStuff() 

失敗以下第一:

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

之後,在類的靜態方法似乎工作(對我來說,使用Grails 2.2.4),我想這是與初始化類,或有事做,但我想:

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

,並沒有工作!

0

Grails領域對象已經嚴重元編程。 代替groovy mixin嘗試:

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