2009-01-08 10 views
10

Estoy tratando de mezclar en una clase en mi aplicación Groovy/Grails, y estoy usando the syntax defined in the docs, pero sigo recibiendo un error.Groovy Mixins?

que tienen una clase de dominio que se parece a esto:

class Person { 
    mixin(ImagesMixin) 

    // ... 
} 

Se compila bien, pero por alguna razón no va a funcionar. El archivo que contiene ImagesMixin se encuentra en mi directorio /src/groovy/.

Lo he probado utilizando las versiones de Groovy 1.5.7 y 1.6-RC1 sin suerte. ¿Alguien sabe lo que estoy haciendo mal?

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

Antes de comenzar a codificar mixins, asegúrese de tener en cuenta las implicaciones de rendimiento. – user339047

Respuesta

4

Creo que lo que he visto hay más bien una propuesta de una característica;) Groovy no soporta mixins fuera de la caja de esta manera todavía (si alguna vez). Pero hay una lib de terceros que se puede usar para emular dicho comportamiento: Injecto. Y mixins se puede definir utilizando AST-Macros en la versión 1.6 de Groovy (que aún no es definitiva).

Siempre debe verificar si está leyendo los documentos del proyecto groovy real o del proyecto GroovyJSR (que es más bien un lugar donde se recogen las propuestas).

Otra forma es utilizar el viejo MOP para inyectar el comportamiento en clases geniales modificando metaClasses.

Saludos

1

FYI: hay una cosa tal como dominios de "incrustados" en Grails ahora, pero tiene problemas. Aquí es donde puede incluir lógicamente un dominio como parte de otro y todos sus campos se producen físicamente en la tabla de una base de datos. Por ejemplo, si encuentra que tiene el mismo subconjunto de campos que aparecen en varias tablas, como la dirección de la calle/ciudad/estado/zip, puede definir un dominio StreetAddress e incrustarlo. Uno de los problemas actuales es que Grails aún creará una tabla street_address además de incrustar sus campos en las otras tablas (a menos que juegues trucos). Parece que hay parches enviados pendientes para esto.

11

No creo que esté utilizando la sintaxis de mixin adecuada. Prueba esto:

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

class Person {} 

Person.mixin MyMixin 

new Person().doStuff()
+0

debería 'doStuff()' realmente ser estático? – Armand

+0

Sí, tiene que serlo. –

+0

Esta solución no funciona: Person.doStuff() falla, que es el objetivo de crear un método estático, para usarlo en un contexto estático, ¿no? ; -) Las mixinas estáticas Groovy aún están rotas a partir de 1.8, quizás en 2.0 tendremos mixins estáticos en funcionamiento. Hasta entonces, tienes que metaClass MOP estática de padres en clase (s) de niños, que es menos que ideal. Toma lo bueno con lo malo, en general Groovy es genial, y, yo también, en aumento. – virtualeyes

12

Desde Groovy 1.6 Puede aplicar un mixin en tiempo de compilación para una clase utilizando una anotación

@Mixin(ImagesMixin) 
class Person { 
} 

O se puede aplicar el mixin en tiempo de ejecución así:

def myMixin = ImagesMixin 
Person.mixin myMixin 

El último enfoque es más dinámico ya que la clase a mixin se puede determinar en tiempo de ejecución. Se puede obtener más información sobre Groovy mixins here.

En mi experiencia, una gran cantidad de meta-programación de clases de dominio simplemente no funciona. No sé exactamente por qué, pero sospecho que se debe al hecho de que estas clases ya están muy metaprogramadas por el tiempo de ejecución de Grails.En general mi enfoque es

  • Prueba el meta-programación en un POGO en la consola maravillosa
  • Si funciona, probarlo en una clase no es de dominio en las Griales consola
  • Si eso funciona, intente en una clase de dominio en la consola de Grails. Si no funciona, debe ser porque es una clase de dominio (en lugar de un problema con la sintaxis). En este punto, es aconsejable tratar de encontrar otra forma de lograr su objetivo. Si eso no es posible, entonces use una combinación de la lista de correo de Grails y/o Stackoverflow y/o el código fuente de Grails para tratar de que la meta-programación funcione.
2

En caso de que esto ayude a, raíz de @virtualeyes comentario anterior, me he dado cuenta que

Person.doStuff() 

falla a menos que se llama a la siguiente primero:

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

después de lo cual, el método estático en la clase parece funcionar (para mí, usando Grails 2.2.4) Supongo que tiene que ver con la inicialización de la clase, o algo así, pero lo intenté:

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

y eso no funcionó!

0

Los objetos del dominio Grails ya están muy metaprogramados. En lugar de mezclar groovy pruebe:

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

También es importante tener en cuenta que los métodos de Gorm que grails add vienen después de que los métodos se agregan a través de mixin y no podrás llamarlos desde el método mixto así que quizás necesites agregar el objeto de dominio como argumento a cualquier combinación en los métodos si tiene la intención de referirse a los buscadores dinámicos o la sesión de hibernación o lo que sea. – Dave