我使用的是Scala 2.9.1
我已经定义了一个Logging trait:
trait Logging {
def debug(msg: String, throwables: Throwable*) = ....
....
}
我有一个jmpublisher类,它混合了日志特性:
class JMSPublisher extends Publisher with Logging {
def publishProducts(list: List[_ <: Product]) = ....
def publish(list: Seq[Product]) = ....
}
这一切都编译良好。我的问题是,我有一个用户想要加载我的jmpublisher到Spring中。他正在使用Spring 2.5.6。
当ApplicationContext在启动过程中被加载时,应用程序崩溃并抛出一个IllegalStateException,抱怨它找不到与我的Logging trait相关的桥接方法。
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。
有人遇到这个问题吗?有什么解决办法或变通办法吗?
我们看到了同样的事情。我一直不知道Scala 2.9有什么变化。x触发了这个问题,但我认为真正的问题在于Spring本身。
当你将一个trait混合到一个类中时,会在类中添加合成方法,在字节码中标记为桥接方法,转发到trait中方法的实现。
Java还为类添加了桥接方法,当子类覆盖超类或接口中的方法时,但会细化返回类型。因为返回类型是字节码级别方法签名的一部分,所以需要一个转发方法,以便只知道父方法签名的客户端仍然可以在子类中调用该方法。(更多细节:What Method。isBridge用于?)
Spring检查字节码中的桥方法,原因在文章A bridge Too Far中描述过。那篇文章的名字很讽刺——Spring称这是"Spring解决Java开发人员面临的硬基础设施问题并将其集成到应用程序堆栈中的完美示例",但它对字节码的源做了太多假设,更糟糕的是,无法禁用。短期的解决方法是避免在Spring中使用的类中混合trait。您应该在Spring中提交一个bug,以允许您对非java字节码禁用此检查。