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

标签 rest grails groovy

我在 rest-api 下生成了 Controller grails 应用程序配置文件。 Controller 中没有任何变化,只是添加了一些 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

提前致谢。

最佳答案

该代码不应该编译,但 Groovy 有时过于“有用”并允许它通过。您将实例变量命名为与其类相同的名称,TSCell ,结果证明这是一个有趣的代码块,用于了解 Groovy 如何处理实例和静态方法调用之间的歧义。

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

在第三行中,不清楚是否正在检查类或实例变量是否为空,但我在本地尝试过,它是实例变量。
TSCell.hasErrors()可以解释为对类的静态方法调用或对实例的调用,但由于该方法不是静态的,Groovy 会在实例上调用它并成功。相同的逻辑必须应用于 save调用,但同样因为它不是静态方法,所以它调用实例并成功。

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

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

关于rest - 为什么默认的 Controller 实现会发送带有内部错误的崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40256099/

相关文章:

grails - 从<g:select下拉列表中获取所选值

Groovy 真相 : string to boolean inconsistency?

python - Django Rest API urlsplit错误

java - 为什么 HTTP 方法 PUT 应该是幂等的而不是实现 RestFul 服务中的 POST?

java - 在一个项目/应用程序 Java 中同时运行 Springboot 和 Rest 端点

spring - 自动化 API 黑盒测试

grails - 在子文件夹中的 Controller 中使用Grails Form标签

java - 仅从命令行获取系统属性列表

java - 解析的 Groovy 脚本的(反)序列化

json - 使用 Groovy JsonSlurper 解析对象数组