2016-12-01 6 views
1

Я хотел бы выполнить некоторую работу, когда новый объект добавляется в домен с отношения hasMany.Grails Overriding domain.addTo

, как, например, для 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 или что-то в этом роде, но это намного более общее и будет ловить каждое обновление, а не просто добавление или удаление из списка.

Обратите внимание, что ошибка, вызванная ошибкой null, указана в сообщении в этом разделе 7 лет назад (по-видимому, вызвана тем, что faiilure инициирует набор), а скорее InvocationTargetException, предотвращающий вызов супер метода из вызываемого вызова.

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) 
+0

Возможный дубликат [Как переопределить AddTo \ * и RemoveFrom \ * GORM/Grails методы] (ХТ tp: //stackoverflow.com/questions/1461857/how-to-override-addto-and-removefrom-gorm-grails-methods) – Gregg

+0

Не думайте так. Этот вопрос не вызвал супер метода addTo. – user1023110

+0

Точно, потому что вы не можете. Рад, что вы получили ответ. – Gregg

ответ

1

Метода домена впрыскивает в классы с помощью меты-программирования или аналогичной техникой, так что нет такой вещи, как 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 = {} 
} 
+0

Спасибо v полезно. Как я могу захватить цель вызова? В этом случае, помимо выполнения дополнения addTo по умолчанию, я хочу внести другие изменения в соответствующее лицо. Это «это» внутри Person.metaClass.blah экземпляр человека? Также могу ли я получить какие-либо параметры, предоставленные методу? – user1023110

+0

внутри закрытия вы должны использовать 'delegate' вместо' this'. Если вы 'println делегировать', вы увидите экземпляр вашего лица на выходе. См. Обновление – injecteer

+0

Фантастическая благодарность. Потребовались бы часы, чтобы понять это. – user1023110

1

Основываясь на комментарии injecteer в выше, ниже это общий метод, чтобы добавить обработчик после 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 
    } 
} 

Чтобы использовать эту функцию, вызовите метод setAfterHandler где-то в Bootstrap или в другом месте, прежде чем пытаться использовать его, например

def success = Meta.setAfterHandler("addToHobby", Person.class, Hobby.class) 

В классе домена, введите ваш обработчик с именем метода after_addTo CollectionName как в примере ниже:

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; 
     } 
    } 
}