2009-01-08 11 views
10

Sto provando a mixare una classe nella mia app Groovy/Grails e sto utilizzando the syntax defined in the docs, ma continuo a ricevere un errore.Groovy Mixins?

ho una classe di dominio che assomiglia a questo:

class Person { 
    mixin(ImagesMixin) 

    // ... 
} 

Si compila bene, ma per qualche motivo non funzionerà. Il file contenente ImagesMixin si trova nella mia directory /src/groovy/.

L'ho provato usando Groovy versioni 1.5.7 e 1.6-RC1 senza fortuna. Qualcuno sa cosa sto sbagliando?

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

Prima di iniziare a programmare i mix, assicurarsi di tenere conto delle implicazioni sulle prestazioni. – user339047

risposta

4

Credo che quello che hai visto non v'è piuttosto una proposta di una caratteristica;) Groovy non supporta ancora mixins fuori dalla scatola in questo modo (se mai). Ma esiste una lib di terze parti che può essere utilizzata per emulare tale comportamento: Injecto. E i mixin possono essere definiti usando AST-Macros nella versione 1.6 di Groovy (che non è ancora definitiva).

Si dovrebbe sempre verificare se si sta leggendo i documenti dal progetto reale groovy o dal progetto GroovyJSR (che è piuttosto un luogo in cui vengono raccolte le proposte).

Un altro modo è usare MOP semplice per iniettare il comportamento in classi groovy modificando metaClass.

Acclamazioni

1

FYI: C'è una cosa come domini "embedded" in Grails ora, ma ha dei problemi. È qui che puoi includere logicamente un dominio come parte di un altro e i suoi campi si verificano tutti fisicamente nella stessa tabella DB. Ad esempio, se si scopre di avere lo stesso sottoinsieme di campi che appare in più tabelle, come l'indirizzo/città/stato/zip, è possibile definire un dominio StreetAddress e incorporarlo. Uno dei problemi attuali è che Grails creerà ancora una tabella street_address oltre a incorporare i suoi campi negli altri tavoli (a meno che non giochi brutti scherzi). Ci sono patch in attesa per questo, a quanto pare.

11

Non penso che si stia utilizzando la corretta sintassi di mixin. Prova questo:

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

class Person {} 

Person.mixin MyMixin 

new Person().doStuff()
+0

dovrebbe 'doStuff()' essere veramente statico? – Armand

+0

Sì, deve essere. –

+0

Questa soluzione non funziona: Person.doStuff() fallisce, che è l'intero punto di creazione di un metodo statico, per utilizzarlo in un contesto statico, giusto? ; -) I mixin statici di Groovy sono ancora interrotti a partire da 1.8, forse nel 2.0 avremo mixin statici funzionanti. Fino ad allora, devi applicare le statistiche genitore di metaClass MOP alle classi figlio, che è meno che ideale. Prendi il buono con il cattivo, Groovy in generale è grande, e, imo, in aumento. – virtualeyes

12

Dal Groovy 1.6 è possibile applicare un mixin a tempo di compilazione per una classe utilizzando un'annotazione

@Mixin(ImagesMixin) 
class Person { 
} 

Oppure si può applicare il mixin in fase di esecuzione in questo modo:

def myMixin = ImagesMixin 
Person.mixin myMixin 

Quest'ultimo approccio è più dinamico in quanto la classe di mixin può essere determinata in fase di esecuzione. Ulteriori informazioni su Groovy mixins sono disponibili here.

Nella mia esperienza, un sacco di meta-programmazione di classi di dominio semplicemente non funziona. Non so esattamente perché, ma sospetto che sia dovuto al fatto che queste classi sono già meticolosamente programmate dal runtime di Grails.In generale, il mio approccio è

  • provare il meta-programmazione su un POGO nella console Groovy
  • Se funziona, provare su una classe non-dominio nelle Grails console
  • Se funziona, provare su una classe di dominio nella console Grails. Se non funziona, allora deve essere perché è una classe dominio (piuttosto che un problema con la sintassi). A questo punto è consigliabile provare e trovare un altro modo per raggiungere il tuo obiettivo. Se ciò non è possibile, utilizzare una combinazione della mailing list di Grails e/o StackOverflow e/o del codice sorgente di Grails per provare a far funzionare la meta-programmazione.
2

Nel caso in cui questo aiuta chiunque, Sulla scia di @virtualeyes commento di cui sopra, ho trovato che

Person.doStuff() 

non riesce a meno che non si chiama la seguente prima:

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

dopo di che, il metodo statico sulla classe sembra funzionare (per me, usando Grails 2.2.4) suppongo che abbia a che fare con l'inizializzazione della classe, o qualcosa del genere, ma ho provato:

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

e che non ha funzionato!

0

Gli oggetti del dominio Grails sono già fortemente programmati. Invece del mixin groovy prova:

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

È anche importante notare che i metodi Gorm che grails aggiunge vengono dopo che i metodi sono stati aggiunti tramite mixin e non sarà possibile richiamarli dal metodo mixed in modo che potrebbe essere necessario aggiungere l'oggetto dominio come argomento a qualsiasi misto nei metodi se si intende fare riferimento a cercatori dinamici o alla sessione di sospensione o qualsiasi altra cosa. – Dave