【问题标题】:Why does using an action name that is the same as a configured SpringBean name result in a ClassCastException?为什么使用与配置的 SpringBean 名称相同的操作名称会导致 ClassCastException?
【发布时间】:2012-08-18 18:21:35
【问题描述】:

要重现此问题,请使用以下步骤。

  1. 创建一个新的 Grails 应用程序。
  2. 创建一个名为 FooController 的新控制器
  3. 向 FooController 添加操作“栏”
  4. 在 src/groovy 中,创建一个名为 Bar 的新类
  5. 在resources.groovy中配置一个名为bar的SpringBean

    bar(Bar) {bean -> bean.autowire = 'byName' }

  6. 启动应用程序并导航到 http:localhost:8080/[appContext]/foo/bar
  7. 你应该得到一个类似这样的堆栈跟踪:

java.lang.ClassCastException: Bar cannot be cast to groovy.lang.Closure at org.grails.plugin.resource.DevModeSanityFilter.doFilter(DevModeSanityFilter.groovy:44) at java.lang.Thread.run(Thread.java:680)'

为什么会出现这种情况?这是 Grails 中的错误还是预期的行为?

我希望配置的 SpringBeans 和操作名称之间不应该有名称冲突。

【问题讨论】:

  • 什么版本的 Grails,如果 2.x 是您的 bar 操作是闭包还是方法?
  • Grails 1.3.7,我也会尝试在 2.x 上重现该问题。
  • 我在 Grails 2.0.3 上试过这个,它使用方法和闭包作为操作都可以正常工作。也许解决方案很明显:升级我用于项目的 Grails 版本。 :-) 我仍然想知道为什么会在 1.3.7 上发生这种情况……感谢您的评论。
  • 在 Grails 2 中,action-as-methods 是首选方法,任何声明为闭包的操作都会在编译时通过 AST 转换处理到方法中。 Spring 仍在用自动装配的 bean 替换控制器的 bar 属性的值,但是当通过 Web 请求调用操作时,它是运行的方法版本(它有自己的原始闭包代码副本)。跨度>

标签: grails classcastexception autowired grails-controller


【解决方案1】:

控制器中的动作是一个闭包,它被转化为一个内部类。你的bean有相同的名字,所以我相信你是通过这个来命名冲突的。您是否尝试重命名 bean 或操作?

【讨论】:

  • 重命名动作或bean显然可以解决问题,但这不是这里的问题......
【解决方案2】:

问题在于 Groovy 语法类似于

class FooController {
  def bar = {
    // do something
  }
}

FooController 类提供两个公共方法

public Object getBar() {
  return bar;
}

public void setBar(Object newBar) {
  bar = newBar;
}

setBar 方法的存在使 Spring 将其视为要自动装配的属性,并将闭包值替换为您的 bean。 Grails 本身只需要 getter 方法,所以如果你说

class FooController {
  final bar = {
    // do something
  }
}

(即声明barfinal)然后Groovy 将只合成getter 而不是setter,Spring 不会将bar 视为它可以自动装配的属性。

【讨论】:

  • 太棒了!我测试了该解决方案,并且该操作现在可以正常工作。我之前曾多次遇到过这个问题,只是更改了动作名称,却没有找到问题的根源。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-28
  • 2020-03-10
  • 1970-01-01
相关资源
最近更新 更多