Отличные миксины?

Я пытаюсь смешать класс в своем приложении Groovy/Grails и использую синтаксис, определенный в документации, но я продолжаю получать сообщение об ошибке.

У меня есть класс домена, который выглядит так:

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 [email protected]:8080

person gabriel    schedule 08.01.2009    source источник
comment
Прежде чем приступить к кодированию примесей, обязательно примите во внимание влияние на производительность.   -  person user339047    schedule 28.02.2012


Ответы (7)


Начиная с Groovy 1.6 вы можете либо применить миксин во время компиляции к классу, используя аннотацию

@Mixin(ImagesMixin)
class Person {
}

Или вы можете применить миксин во время выполнения следующим образом:

def myMixin = ImagesMixin
Person.mixin myMixin

Последний подход более динамичен, так как класс для миксина можно определить во время выполнения. Дополнительную информацию о миксинах Groovy можно найти здесь.

По моему опыту, большая часть метапрограммирования классов предметной области просто не работает. Я точно не знаю почему, но подозреваю, что это связано с тем, что эти классы уже очень сильно метапрограммированы средой выполнения Grails. В общем мой подход

  • Попробуйте метапрограммирование на POGO в консоли Groovy.
  • Если это сработает, попробуйте применить его к классу, не относящемуся к домену, в консоли Grails.
  • Если это сработает, попробуйте применить его к классу предметной области в консоли Grails. Если это не работает, то это должно быть потому, что это класс предметной области (а не проблема с синтаксисом). В этот момент рекомендуется попытаться найти другой способ достижения цели. Если это невозможно, используйте комбинацию списка рассылки Grails и/или Stackoverflow, и/или исходный код Grails, чтобы попытаться заставить работать метапрограммирование.
person Dónal    schedule 13.08.2009

Я не думаю, что вы используете правильный синтаксис миксина. Попробуй это:

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

class Person {}

Person.mixin MyMixin

new Person().doStuff()
person Matthew Taylor    schedule 22.01.2009
comment
должен ли doStuff() быть статичным? - person Armand; 29.03.2011
comment
Это решение не работает: Person.doStuff() терпит неудачу, в чем весь смысл создания статического метода, чтобы использовать его в статическом контексте, верно? ;--) Статические примеси Groovy по-прежнему не работают с версии 1.8, возможно, в версии 2.0 у нас будут работающие статические примеси. До тех пор вы должны преобразовать родительскую статику метакласса MOP в дочерние классы, что далеко не идеально. Сочетайте хорошее с плохим, в целом Groovy великолепен и, имхо, находится на подъеме. - person virtualeyes; 26.04.2011

Я предполагаю, что то, что вы там видели, скорее предложение, чем функция ;) Groovy пока не поддерживает миксины из коробки таким образом (если вообще когда-либо). Но есть сторонняя библиотека, которую можно использовать для имитации такого поведения: Injecto. И миксины можно определить с помощью AST-Macros в версии 1.6 Groovy (которая еще не является окончательной).

Вы всегда должны проверять, читаете ли вы документы из настоящего проекта groovy или из проекта GroovyJSR (который скорее является местом, где собираются предложения).

Другой способ — использовать старый добрый MOP для внедрения поведения в отличные классы путем изменения метаклассов.

Ваше здоровье

person Siegfried Puchbauer    schedule 08.01.2009

На случай, если это кому-нибудь поможет, следуя приведенному выше комментарию @virtualeyes, я обнаружил, что

Person.doStuff()

терпит неудачу, если вы сначала не вызовете следующее:

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

после чего статический метод класса, кажется, работает (для меня, используя Grails 2.2.4). Я думаю, это связано с инициализацией класса или чем-то еще, но я попытался:

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

и это не сработало!

person DarthPablo    schedule 10.08.2013

К вашему сведению: сейчас в Grails есть такая вещь, как «встроенные» домены, но у нее есть проблемы. Здесь вы можете логически включить один домен как часть другого, и все его поля физически появятся в одной таблице БД. Например, если вы обнаружите, что у вас есть одно и то же подмножество полей, появляющееся в нескольких таблицах, например улица/город/штат/почтовый индекс, вы можете определить домен StreetAddress и внедрить его. Одна из текущих проблем заключается в том, что Grails по-прежнему будет создавать таблицу street_address в дополнение к встраиванию ее полей в другие таблицы (если только вы не будете хитрить). Кажется, для этого есть представленные патчи.

person Community    schedule 21.01.2009

Объекты предметной области Grails уже сильно метапрограммированы. Вместо заводного миксина попробуйте:

@grails.util.Mixin(ImagesMixin)
    class Person {
}
person Dave    schedule 12.09.2014
comment
Также важно отметить, что методы Gorm, которые добавляет Grails, появляются после того, как методы добавляются через миксин, и вы не сможете вызывать их из смешанного метода, поэтому вам может потребоваться добавить объект домена в качестве аргумента для любого смешанного. методы, если вы собираетесь ссылаться на динамические средства поиска или сеанс гибернации или что-то еще. - person Dave; 12.09.2014

Используйте черты!

Черты — это причина, по которой они убрали поддержку миксинов, потому что они просто лучше. Это в основном абстрактные классы, которые реализованы. Позволяет вам использовать несколько и работать с ними как с частичными классами.

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

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

new B().printAnything() 

Попробуйте!

person Adam Taylor    schedule 22.10.2018