为什么默认的Controller实现会发送内部错误的崩溃?

时间:2016-10-26 07:22:52

标签: rest grails groovy

我在rest-api grails app个人资料下生成了控制器。控制器没有任何改变,只添加了一些println调用。

对于来电curl -X PUT -d name=petr2 -d phone=338 localhost:8080/TSCell/3我有{"message":"Internal server error","error":500}回复。在调试中我可以看到,在最后respond TSCell, [status: OK, view:"show"]调用后发生了错误。

更新方法代码:

@Transactional
def update(TSCell tSCell) {
    println "in update method"
    if (tSCell == null) {
        transactionStatus.setRollbackOnly()
        render status: NOT_FOUND
        return
    }

    if (tSCell.hasErrors()) {
        transactionStatus.setRollbackOnly()
        respond tSCell.errors, view:'edit'
        return
    }

    tSCell.save flush:true

    respond tSCell, [status: OK, view:"show"]
}

并堆叠跟踪

ERROR org.grails.web.errors.GrailsExceptionResolver - IllegalArgumentException occurred when processing request: [PUT] /TSCell/3
Model variable [TSCell] of with value [class zcrm.api.TSCell] type [java.lang.Class] is not of the correct type [zcrm.api.TSCell]. 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.doPut(FrameworkServlet.java:883)
    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:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: grails.views.ViewRenderException: Error rendering view: Model variable [TSCell] of with value [class zcrm.api.TSCell] type [java.lang.Class] is not of the correct type [zcrm.api.TSCell]
    at grails.views.AbstractWritableScript.writeTo(AbstractWritableScript.groovy:33)
    at grails.views.mvc.GenericGroovyTemplateView.renderMergedOutputModel(GenericGroovyTemplateView.groovy:71)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
    at grails.views.mvc.renderer.DefaultViewRenderer.render(DefaultViewRenderer.groovy:105)
    at grails.artefact.controller.RestResponder$Trait$Helper.internalRespond(RestResponder.groovy:188)
    at grails.artefact.controller.RestResponder$Trait$Helper.respond(RestResponder.groovy:98)
    at zcrm.api.TSCellController$$EQ0icN2W.$tt__update(TSCellController.groovy:64)
    at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:96)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
    at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
    at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:96)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
    at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
    ... 14 common frames omitted
Caused by: java.lang.IllegalArgumentException: Model variable [TSCell] of with value [class zcrm.api.TSCell] type [java.lang.Class] is not of the correct type [zcrm.api.TSCell]
        at grails.views.WritableScriptTemplate.make(WritableScriptTemplate.groovy:138)
    at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper.prepareWritable(DefaultGrailsJsonViewHelper.groovy:736)
    at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper$7.writeTo(DefaultGrailsJsonViewHelper.groovy:713)
    at grails.plugin.json.view.JsonViewTemplate.json(JsonViewTemplate.groovy:126)
    at grails.plugin.json.view.JsonViewTemplate.json(JsonViewTemplate.groovy:149)
    at zcrm_api_TSCell_show_gson.run(zcrm_api_TSCell_show_gson:7)
    at grails.plugin.json.view.JsonViewTemplate.doWrite(JsonViewTemplate.groovy:35)
    at grails.views.AbstractWritableScript.writeTo(AbstractWritableScript.groovy:30)
    ... 26 common frames omitted

提前致谢。

3 个答案:

答案 0 :(得分:2)

该代码不应该编译,但Groovy有时太'有用'而且允许它通过。您将实例变量命名为与其类TSCell相同,这看起来是一个有趣的代码块,用于查看Groovy如何处理实例和静态方法调用之间的消歧。

对于第一行,由于你有TSCell TSCell,编译器可能知道左边的那个是类名,而右边的那个是实例变量,因为没有其他有效的解释那些令牌。

在第三行中,不清楚是否检查了类或实例变量的null,但是我在本地尝试了这个,它是实例变量。

TSCell.hasErrors()可以解释为对类的静态方法调用或对实例的调用,但由于该方法不是静态的,因此Groovy在实例上调用它并成功。必须将同样的逻辑应用于save调用,但是因为它不是静态方法,所以它在实例上调用并成功。

然后在方法的最后一行,kaboom,你的运气在四次成功通话后跑了出来。 respond方法存在一些重载,您最终调用respond(Object, Map),这对TSCell类有效,或TSCell TSCell实例有效} .class。 Groovy选择了一个不是你想要的那个和respond方法中不支持的那个。

Groovy共享Java的变量和类命名约定,即类名以大写字母开头,实例变量名以小写字母开头。告诉人们这是一个很好的方法是一回事,但这样的例子使得更明显的是为什么使用大写的实例变量名称是个坏主意(你应该能够看到变量而不需要看到它的声明,知道它是一个类或var名称)以及为什么使用与该类相同的名称更糟糕。

答案 1 :(得分:1)

此错误可能是因为您将参数命名为类名。

我建议您将变量的名称更改为小写(这是groovy和java命名约定)。

def update(TSCell tsCell) { //you can also just write tsCell without type
    println "in update method"
    if (tsCell == null) {
        transactionStatus.setRollbackOnly()
        render status: NOT_FOUND
        return
    }

    if (tsCell.hasErrors()) {
        transactionStatus.setRollbackOnly()
        respond tsCell.errors, view:'edit'
        return
    }

    tsCell.save flush:true

    respond tsCell, [status: OK, view:"show"]
}

答案 2 :(得分:0)

问题在于电话curl。正如documentation所说Grails has built in support for Content negotiation using either the HTTP Accept header, an explicit format request parameter or the extension of a mapped URI.

因此,在上述-H "Accept: application/xml"调用中添加curl即可解决问题。