Почему я не могу обернуть withRest() своим собственным методом и запустить замыкание внутри него?

Плагин HTTPBuilder для Griffon великолепен и очень хорошо упрощает мои звонки на сервер. Единственная проблема, однако, в том, что я не хочу повторять один и тот же код установки повсюду.

То, что я хочу сделать, это обернуть набор серверных вызовов и другой код с той же настройкой соединения, чтобы у меня он был только в одном месте.

Как пример, это то, что у меня есть:

def persistCurrentSession() {
    withRest(uri: serverBaseURL) {
        headers = requestHeaders

        post(path: "${sessionBaseURL}${currentSession.id}",
                body: currentSession,
                requestContentType: groovyx.net.http.ContentType.JSON)
    }
}

def refreshCurrentSession() {
    withRest(uri: serverBaseURL) {
        headers = requestHeaders

        currentSession = get(path: "${sessionBaseURL}${currentSession.id}").responseData.sessionInstance
    }
}

И это то, что я хочу сделать:

def persistCurrentSession() {
    withMyRest {
        post(path: "${sessionBaseURL}${currentSession.id}",
                body: currentSession,
                requestContentType: groovyx.net.http.ContentType.JSON)
    }
}

def refreshCurrentSession() {
    withMyRest {
        currentSession = get(path: "${sessionBaseURL}${currentSession.id}").responseData.sessionInstance
    }
}

def withMyRest(Closure stmts) {
    withRest(uri: serverBaseURL) {
        headers = requestHeaders
        stmts()
    }
}

Из того, что я знаю о Groovy и замыканиях, это должно быть очень полезно для замыканий, так как оно удаляет общий код "установки / разрыва ресурсов" в одном месте и позволяет сосредоточиться на сути серверных вызовов.

Проблема в том, что не похоже, что динамические методы добавляются должным образом, потому что когда я запускаю код, настраиваю его так, как я хочу, MissingMethodExceptionкогда меня бросают stmts() вызывается:

2011-12-20 11:12:40,097 [pool-2-thread-1] ERROR griffon.util.GriffonExceptionHandler - Uncaught Exception
org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: client.MyAppServerService.post() is applicable for argument types: (java.util.LinkedHashMap) values: [[path:http://localhost:8080/Server/session/4, ...]]
Possible solutions: wait(), wait(long), print(java.lang.Object), use([Ljava.lang.Object;), is(java.lang.Object), split(groovy.lang.Closure)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1053)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1071)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at groovy.lang.Closure.call(Closure.java:410)
    at groovy.lang.Closure.call(Closure.java:404)
    at groovy.lang.Closure.run(Closure.java:488)
    at org.codehaus.griffon.runtime.util.AbstractUIThreadHandler$1.run(AbstractUIThreadHandler.java:41)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
Caused by: groovy.lang.MissingMethodException: No signature of method: client.MyAppServerService.post() is applicable for argument types: (java.util.LinkedHashMap) values: [[path:http://localhost:8080/Server/session/4, ...]]
Possible solutions: wait(), wait(long), print(java.lang.Object), use([Ljava.lang.Object;), is(java.lang.Object), split(groovy.lang.Closure)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at client.MyAppServerService$_persistCurrentSession_closure2.doCall(MyAppServerService.groovy:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:226)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at client.MyAppServerService$_persistCurrentSession_closure2.doCall(MyAppServerService.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1053)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1071)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at groovy.lang.Closure.call(Closure.java:410)
    at groovy.lang.Closure.call(Closure.java:404)
    at java_util_concurrent_Callable$call.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at client.MyAppServerService$_withMyRest_closure4.doCall(MyAppServerService.groovy:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:226)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at client.MyAppServerService$_withMyRest_closure4.doCall(MyAppServerService.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1053)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1071)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883)
    at groovy.lang.Closure.call(Closure.java:410)
    at groovy.lang.Closure.call(Closure.java:404)
    at java_util_concurrent_Callable$call.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at java_util_concurrent_Callable$call.call(Unknown Source)
    at griffon.plugins.rest.RestConnector.doWithBuilder(RestConnector.groovy:90)
    at griffon.plugins.rest.RestConnector.this$2$doWithBuilder(RestConnector.groovy)
    at griffon.plugins.rest.RestConnector$this$2$doWithBuilder.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at griffon.plugins.rest.RestConnector$this$2$doWithBuilder.callCurrent(Unknown Source)
    at griffon.plugins.rest.RestConnector.withRest(RestConnector.groovy:67)
    at griffon.plugins.rest.RestConnector$withRest.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at griffon.plugins.rest.RestConnector$withRest.call(Unknown Source)
    at griffon.plugins.rest.RestConnector$_enhance_closure5.doCall(RestConnector.groovy:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod.invoke(ClosureMetaMethod.java:80)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoMetaMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:308)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
    at client.MyAppServerService.withMyRest(MyAppServerService.groovy:68)
    at client.MyAppServerService$withMyRest.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at client.MyAppServerService.persistCurrentSession(MyAppServerService.groovy:48)
    at client.MyAppServerService$persistCurrentSession.callCurrent(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:137)
    at client.MyAppServerService.closeSession(MyAppServerService.groovy:41)
    at client.MyAppServerService$closeSession.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at client.StartController$_closure1_closure2.doCall(StartController.groovy:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:226)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
    at client.StartController$_closure1_closure2.doCall(StartController.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    ... 14 more

Я уверен, что есть лучшие способы сделать то, что я пытаюсь сделать, но даже в этом случае то, что я пытаюсь сделать, должно работать, я думаю. Я все еще новичок в Groovy, но я несколько раз перебирал правила области видимости, и все, о чем я могу думать, - это то, что динамические методы для HTTPBuilder не подключаются должным образом через пропущенные замыкания или что-то в этом роде.

1 ответ

Решение

Похоже, происходит то, что делегат закрытия теряется. Делегаты являются важной частью того, как работают классные замыкания. Каждое замыкание имеет связанный с ним объект делегата, и любые методы, вызываемые в замыкании, могут быть вызваны в делегате. Точный порядок настраивается с помощью Closure.setResolveStrategy, но по умолчанию сначала используется метод для владельца (где объявляется закрытие), а затем для делегата. Вы всегда можете явно указать делегат внутри замыкания с помощью delegate,

Делегаты являются основным механизмом предоставления таких волшебных динамических методов, как setHeaders(), Когда HttpBuilder вызывает передаваемое вами замыкание, он устанавливает делегат явного замыкания, но stmts() пропускается Все, что вам нужно сделать, это передать делегату stmts(), Попробуйте что-то вроде этого:

def withMyRest(Closure stmts) {
    withRest(uri: serverBaseURL) {
        headers = requestHeaders
        stmts.delegate = delegate
        stmts()
    }
}
Другие вопросы по тегам