6

我正在使用 Scala 2.9.1

我已经这样定义了一个 Logging 特征:

 trait Logging {
    def debug(msg: String, throwables: Throwable*) = ....
    ....
 }

我有一个 JMSPublisher 类,它混合了 Logging 特征:

 class JMSPublisher extends Publisher with Logging {
    def publishProducts(list: List[_ <: Product]) = ....
    def publish(list: Seq[Product]) = ....
 }

这一切都编译得很好。我的问题是我有一个用户想要将我的 JMSPublisher 加载到 Spring 中。他正在使用 Spring 2.5.6。

在启动期间加载 ApplicationContext 时,应用程序崩溃并出现 IllegalStateException,抱怨它找不到与我的 Logging 特征相关的桥接方法。

Initialization of bean failed; nested exception is java.lang.IllegalStateException: Unable to locate bridged method for bridge method 'public void com.app.messaging.JmsPublisher.debug(java.lang.String, scala.collection.Seq)' 
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480)
    .....stack trace follows.......

这段代码在 Scala-2.8 下工作,我听说 Scala 正在标记具有一些在 2.9 中桥接的方法的 trait。我认为这就是导致 Spring 失败的原因。如果 Spring 无法加载我的类,我将无法升级到 Scala-2.9。

有没有人遇到过这个问题?是否有任何修复或解决方法?

4

1 回答 1

3

我们看到了同样的事情。我从来不知道 Scala 2.9.x 中的什么变化触发了这个,但我认为真正的问题在于 Spring 本身。

当您将 trait 混合到一个类中时,在类中添加合成方法,在字节码中标记为桥方法,转发到 trait 中方法的实现。

当子类覆盖超类或接口中的方法但改进返回类型时,Java 还会向类添加桥接方法。因为返回类型是字节码级别的方法签名的一部分,所以需要一个转发方法,以便只知道父方法签名的客户端仍然可以调用子类中的方法。(更多细节:Method.isBridge 用于什么?

Spring 检查桥接方法的字节码,原因在文章A Bridge Too Far中描述。那篇文章的名字很讽刺——Spring 称其为“Spring 解决 Java 开发人员面临的硬基础设施问题并将其集成到应用程序堆栈中的完美示例”,但它对字节码的来源做出了太多假设,并且更糟糕的是,不能禁用。

短期解决方法是避免将特征混入您在 Spring 中使用的类中。您应该向 Spring 提交一个错误,以允许您禁用对非 Java 字节码的此检查。

于 2011-11-06T20:07:04.887 回答