Grails 覆盖 domain.addTo
Grails Overriding domain.addTo
我想在将新对象添加到具有 hasMany 关系的域时做一些工作。
例如,对于 Person hasMany Hobby
在拦截器中为 addToHobby()
和 removeFromHobby()
做一些工作如下:
class Person {
String name
boolean likesFishing
static hasMany = [hobby: Hobby]
addToHobby(Hobby h) {
super.addToHobby(h) //*throws missingMethod exception
if (h.name="Fishing") {this.likesFishing=true;}
}
removeFromHobby(Hobby h) {
super removeFromHobby(h)
if (h.name="Fishing") {this.likesFishing=false;}
}
}
出于某种原因,抛出了一个错误,我猜这与 Gorm 正在完成的一些神奇工作有关,而当方法被覆盖时,这些工作没有完成。无论如何围绕这个?我可以将这种东西放在 beforeUpdate 或类似的东西中,但它更通用并且会捕获每次更新,而不仅仅是列表中的添加或删除。
注意抛出的错误不是7年前post中关于这个话题的空指针异常(显然是由于启动Set失败引起的),而是一个InvocationTargetException阻止super方法正在呼叫。
No signature of method: testapp.Person.addToHobby() is applicable for argument types: (testapp.Hobby) values: [testapp.Hobby : (unsaved)]
Possible solutions: addToHobby(testapp.Hobby), addToHobby(java.lang.Object), getHobby(). Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:210)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:187)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
域方法是通过元编程或类似技术注入到您的 类 中的,因此没有 super.addTo*()
这样的东西。
最简单的方法是使用您提到的 interceptors
,或者您可以添加自己的元方法来覆盖 GORM 的默认 addTo
。
例如:
class BootStrap {
def init = { servletContext ->
def oldAddToHobby = Person.metaClass.getMetaMethod 'addToHobby'
Person.metaClass.addToHobby{ Hobby h ->
oldAddToHobby.invoke delegate, h
println 'blah 2'
}
}
def destroy = {}
}
根据上述注入者的评论,下面是在 addTo 之后添加处理程序的通用方法(或任何其他采用单个参数的动态方法)。
public class Meta {
static boolean setAfterHandler(String methodName, Class sourceClass, Class paramClass) {
//get the method
MetaMethod mymethod = sourceClass.metaClass.getMetaMethod(methodName)
if (mymethod==null) return false
//if after_ handler exists, update the metaClass to call the
// dynamic method, and then the after_ method handler. r
if (sourceClass.newInstance().respondsTo("after_${methodName}")) {
sourceClass.metaClass."${methodName}" {myParam ->
mymethod.invoke delegate, myParam
delegate."after_${methodName}"(myParam);
}
return true
} else {
return false
}
}
要使用它,请在 Bootstrap 或其他地方的某处调用 setAfterHandler 方法,然后再尝试使用它,例如
def success = Meta.setAfterHandler("addToHobby", Person.class, Hobby.class)
在您的域 class 中,使用方法名称 after_addToCollectionName 插入您的处理程序,如下例所示:
class Person {
String first
String last
Integer age
boolean likesFishing=false
static hasMany = [hobby: Hobby]
static constraints = {
}
void after_addToHobby(Hobby h) {
if (h.name=="Fishing") {
this.likesFishing=true;
}
}
}
从另一个角度解决这个问题可能会更有趣:...
class Hobby {
String name
static belongsTo = [person: Person]
setPerson(Person p) {
this.person = p
if (name="Fishing") {p.likesFishing=true;}
}
Person getPerson() {
return this.person
}
}
我想在将新对象添加到具有 hasMany 关系的域时做一些工作。
例如,对于 Person hasMany Hobby
在拦截器中为 addToHobby()
和 removeFromHobby()
做一些工作如下:
class Person {
String name
boolean likesFishing
static hasMany = [hobby: Hobby]
addToHobby(Hobby h) {
super.addToHobby(h) //*throws missingMethod exception
if (h.name="Fishing") {this.likesFishing=true;}
}
removeFromHobby(Hobby h) {
super removeFromHobby(h)
if (h.name="Fishing") {this.likesFishing=false;}
}
}
出于某种原因,抛出了一个错误,我猜这与 Gorm 正在完成的一些神奇工作有关,而当方法被覆盖时,这些工作没有完成。无论如何围绕这个?我可以将这种东西放在 beforeUpdate 或类似的东西中,但它更通用并且会捕获每次更新,而不仅仅是列表中的添加或删除。
注意抛出的错误不是7年前post中关于这个话题的空指针异常(显然是由于启动Set失败引起的),而是一个InvocationTargetException阻止super方法正在呼叫。
No signature of method: testapp.Person.addToHobby() is applicable for argument types: (testapp.Hobby) values: [testapp.Hobby : (unsaved)]
Possible solutions: addToHobby(testapp.Hobby), addToHobby(java.lang.Object), getHobby(). Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:210)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:187)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
域方法是通过元编程或类似技术注入到您的 类 中的,因此没有 super.addTo*()
这样的东西。
最简单的方法是使用您提到的 interceptors
,或者您可以添加自己的元方法来覆盖 GORM 的默认 addTo
。
例如:
class BootStrap {
def init = { servletContext ->
def oldAddToHobby = Person.metaClass.getMetaMethod 'addToHobby'
Person.metaClass.addToHobby{ Hobby h ->
oldAddToHobby.invoke delegate, h
println 'blah 2'
}
}
def destroy = {}
}
根据上述注入者的评论,下面是在 addTo 之后添加处理程序的通用方法(或任何其他采用单个参数的动态方法)。
public class Meta {
static boolean setAfterHandler(String methodName, Class sourceClass, Class paramClass) {
//get the method
MetaMethod mymethod = sourceClass.metaClass.getMetaMethod(methodName)
if (mymethod==null) return false
//if after_ handler exists, update the metaClass to call the
// dynamic method, and then the after_ method handler. r
if (sourceClass.newInstance().respondsTo("after_${methodName}")) {
sourceClass.metaClass."${methodName}" {myParam ->
mymethod.invoke delegate, myParam
delegate."after_${methodName}"(myParam);
}
return true
} else {
return false
}
}
要使用它,请在 Bootstrap 或其他地方的某处调用 setAfterHandler 方法,然后再尝试使用它,例如
def success = Meta.setAfterHandler("addToHobby", Person.class, Hobby.class)
在您的域 class 中,使用方法名称 after_addToCollectionName 插入您的处理程序,如下例所示:
class Person {
String first
String last
Integer age
boolean likesFishing=false
static hasMany = [hobby: Hobby]
static constraints = {
}
void after_addToHobby(Hobby h) {
if (h.name=="Fishing") {
this.likesFishing=true;
}
}
}
从另一个角度解决这个问题可能会更有趣:...
class Hobby {
String name
static belongsTo = [person: Person]
setPerson(Person p) {
this.person = p
if (name="Fishing") {p.likesFishing=true;}
}
Person getPerson() {
return this.person
}
}