Я пытаюсь добавить класс в свое приложение 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





Я предполагаю, что то, что вы видели, скорее предложение, чем функция;) Groovy пока не поддерживает миксины из коробки таким образом (если вообще когда-либо). Но есть сторонняя библиотека, которую можно использовать для эмуляции такого поведения: Injecto. И миксины могут быть определены с помощью AST-Macros в версии Groovy 1.6 (которая еще не является окончательной).
Вы всегда должны проверять, читаете ли вы документацию из настоящего Groovy-проекта или из проекта GroovyJSR (который, скорее, является местом, где собираются предложения).
Другой способ - использовать старый добрый MOP для внедрения поведения в классные классы путем изменения метаклассов.
Ваше здоровье
К сведению: сейчас в Grails есть такое понятие, как «встроенные» домены, но с ним есть проблемы. Здесь вы можете логически включить один домен как часть другого, и все его поля будут физически присутствовать в одной таблице БД. Например, если вы обнаружите, что у вас есть одно и то же подмножество полей, появляющееся в нескольких таблицах, например, уличный адрес / город / штат / почтовый индекс, вы можете определить домен StreetAddress и встроить его. Одна из текущих проблем заключается в том, что Grails по-прежнему будет создавать таблицу street_address в дополнение к встраиванию ее полей в другие таблицы (если вы не играете в трюки). Похоже, для этого есть отправленные исправления.
Я не думаю, что вы используете правильный синтаксис миксина. Попробуй это:
class MyMixin {
static doStuff(Person) {
'stuff was done'
}
}
class Person {}
Person.mixin MyMixin
new Person().doStuff()должен ли doStuff() быть статичным?
Это решение не работает: Person.doStuff () не работает, в чем весь смысл создания статического метода, чтобы использовать его в статическом контексте, верно? ; -) Статические миксины Groovy все еще не работают, начиная с 1.8, возможно, в 2.0 у нас будут рабочие статические миксины. До тех пор вам нужно перенести родительскую статику MOP в дочерний класс (классы), что далеко не идеально. Возьмите хорошее к плохому, в целом Groovy великолепен, и, я думаю, он находится на подъеме.
Начиная с Groovy 1.6, вы можете применить миксин во время компиляции к классу с помощью аннотации.
@Mixin(ImagesMixin)
class Person {
}
Или вы можете применить миксин во время выполнения следующим образом:
def myMixin = ImagesMixin
Person.mixin myMixin
Последний подход более динамичен, поскольку класс для микширования может быть определен во время выполнения. Дополнительная информация о миксинах Groovy доступна в здесь.
По моему опыту, многие методы метапрограммирования классов предметной области просто не работают. Я точно не знаю почему, но подозреваю, что это связано с тем, что эти классы уже очень сильно метапрограммированы средой выполнения Grails. В целом мой подход
В случае, если это кому-то поможет, следуя приведенному выше комментарию @virtualeyes, я обнаружил, что
Person.doStuff()
завершится ошибкой, если вы сначала не вызовете следующее:
new Person().doStuff()
Person.doStuff()
после чего статический метод класса, похоже, работает (для меня, используя Grails 2.2.4), я думаю, это связано с инициализацией класса или чем-то еще, но я попробовал:
Person.metaClass.initialize()
Person.doStuff()
и это не сработало!
Объекты предметной области Grails уже сильно метапрограммированы. Вместо заводного миксина попробуйте:
@grails.util.Mixin(ImagesMixin)
class Person {
}
Также важно отметить, что методы Gorm, которые добавляет grails, появляются после того, как методы добавлены через mixin, и вы не сможете вызывать их из смешанного метода, поэтому вам может потребоваться добавить объект домена в качестве аргумента к любому смешанному методу. методы, если вы собираетесь ссылаться на динамические средства поиска или сеанс гибернации или что-то еще.
Используйте черты характера!
Черты - причина, по которой они удалили поддержку миксинов, потому что они просто лучше. Это в основном реализованные абстрактные классы. Позволяет использовать несколько классов и управлять ими как частичными классами.
trait A {
void printSomething() {
println "foobar"
}
}
class B implements A {
void printAnything() {
printSomething()
}
}
new B().printAnything()
Попробуйте!
Прежде чем приступить к написанию миксинов, обязательно примите во внимание влияние на производительность.