2009-01-08 19 views
10

Ich versuche eine Klasse in meiner Groovy/Grails App zu mischen, und ich benutze the syntax defined in the docs, aber ich bekomme immer einen Fehler.Groovy Mixins?

Ich habe eine Domain-Klasse, die wie folgt aussieht:

class Person { 
    mixin(ImagesMixin) 

    // ... 
} 

Es kompiliert gut, aber aus irgendeinem Grund wird es nicht funktionieren. Die Datei mit ImagesMixin befindet sich in meinem Verzeichnis /src/groovy/.

Ich habe es mit den Groovy-Versionen 1.5.7 und 1.6-RC1 ohne Glück versucht. Weiß jemand was ich falsch mache?

Stacktrace:

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

Bevor Sie Codierung Mixins beginnen, stellen Sie sicher, dass zu berücksichtigen Auswirkungen auf die Leistung nehmen. – user339047

Antwort

4

Ich denke, was du da gesehen habe ist eher ein Vorschlag als ein Merkmal;) Groovy Mixins aus der Box auf diese Weise noch nicht unterstützt (wenn überhaupt). Aber es gibt eine dritte Partei-Lib, die verwendet werden kann, um ein solches Verhalten zu emulieren: Injecto. Und Mixins können mit AST-Macros in der Version 1.6 von Groovy (die noch nicht final ist) definiert werden.

Sie sollten immer überprüfen, ob Sie die Dokumente aus dem echten Groovy-Projekt oder aus dem GroovyJSR-Projekt (das eher ein Ort ist, an dem Vorschläge gesammelt werden) lesen.

Eine andere Möglichkeit ist die Verwendung von Plain-Old-MOP, um Verhalten in groovige Klassen zu injizieren, indem Meta-Klassen modifiziert werden.

Prost

1

Zur Info: Es gibt so etwas wie eine „eingebettete“ Domains in Grails jetzt, aber es hat Probleme. Hier können Sie logisch eine Domäne als Teil einer anderen einschließen, deren Felder alle physikalisch in der einen DB-Tabelle vorkommen. Wenn Sie beispielsweise feststellen, dass in mehreren Tabellen die gleiche Teilmenge von Feldern vorhanden ist, z. B. Straße/Ort/Stadt/Bundesland/PLZ, können Sie eine StreetAddress-Domäne definieren und diese einbetten. Eines der aktuellen Probleme ist, dass Grails weiterhin eine street_address -Tabelle erstellen wird, zusätzlich zu den Feldern in den anderen Tabellen (außer Sie spielen Tricks). Es gibt anscheinend ausstehende Patches für dieses Problem.

11

Ich glaube nicht, dass Sie die richtige Mixin-Syntax verwenden. Versuchen Sie folgendes:

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

class Person {} 

Person.mixin MyMixin 

new Person().doStuff()
+0

sollte 'doStuff()' wirklich statisch sein? – Armand

+0

Ja, es muss sein. –

+0

Diese Lösung funktioniert nicht: Person.doStuff() schlägt fehl, was ist der Sinn der Erstellung einer statischen Methode, um sie in einem statischen Kontext zu verwenden, richtig? ; -) Groovy statische Mixins sind immer noch ab 1.8 kaputt, vielleicht in 2.0 werden wir statische Mixins haben. Bis dahin müssen Sie die MOP-Elternstatik auf die Kindklasse (n) metaClass, was weniger als ideal ist. Nimm das Gute mit dem Schlechten, insgesamt ist Groovy großartig und, imo, auf dem Vormarsch. – virtualeyes

12

Da Groovy 1.6 Sie entweder eine mixin zur Compile-Zeit zu einer Klasse anwenden können eine Anmerkung mit

@Mixin(ImagesMixin) 
class Person { 
} 

Oder Sie können die mixin zur Laufzeit wie folgt anwenden:

def myMixin = ImagesMixin 
Person.mixin myMixin 

der letztere Ansatz ist dynamischer als die Klasse zu mixin kann zur Laufzeit bestimmt werden. Weitere Informationen zu Groovy Mixins erhalten Sie unter here.

Nach meiner Erfahrung vieler Meta-Programmierung von Domain-Klassen funktionieren einfach nicht. Ich weiß nicht genau warum, aber ich vermute, es liegt daran, dass diese Klassen bereits sehr stark von der Grails-Laufzeit metaprogrammiert sind.Im Allgemeinen mein Ansatz ist

  • Versuchen Sie, die Meta-Programmierung auf einem POGO in der Groovy Konsole
  • Wenn das funktioniert, versuchen Sie es auf einem Nicht-Domain-Klasse in den Grails Konsole
  • Wenn das funktioniert, versuchen es auf einer Domain-Klasse in der Grails-Konsole. Wenn es nicht funktioniert, dann muss es sein, weil es eine Domain-Klasse ist (anstatt ein Problem mit der Syntax). An diesem Punkt ist es ratsam zu versuchen, einen anderen Weg zu finden, um Ihr Ziel zu erreichen. Wenn das nicht möglich ist, verwenden Sie eine Kombination aus der Grails-Mailing-Liste und/oder Stackoverflow und/oder dem Grails-Quellcode, um zu versuchen, die Meta-Programmierung zum Laufen zu bringen.
2

Falls dies jemand hilft, von @virtualeyes Kommentar über Anschluss an habe ich festgestellt, dass

Person.doStuff() 

schlägt fehl, wenn Sie zuerst das folgende nennen:

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

wonach die statische Methode für die Klasse scheint zu funktionieren (für mich, mit Grails 2.2.4) Ich denke, es ist mit der Initialisierung der Klasse oder etwas zu tun, aber ich habe versucht:

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

und das hat nicht funktioniert!

0

Grails Domain-Objekte sind bereits stark meta-programmiert. Anstelle der groovy mixin try:

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

Es ist auch wichtig zu beachten, dass Gorm-Methoden, die Grails hinzufügen, kommen, nachdem die Methoden über Mixin hinzugefügt wurden und Sie sie nicht mehr aus der Mixed-In-Methode aufrufen können in Methoden, wenn Sie auf dynamische Finder oder die Ruhezustand-Sitzung oder was auch immer beziehen möchten. – Dave