java - 简单选择上的 lambdaJ 和 ClassCastException

标签 java classloader classcastexception cglib lambdaj

我的想法用完了,谷歌也没有帮助。用例似乎微不足道,但它因 ClassCastException 而失败。我不知道我做错了什么。 有一个简单的方法可以返回与给定类别匹配的第一个元素,请看一看。

private Category selectElement(List<? extends Category> results, Code code) {
    return selectFirst(results, having(on(Category.class).getCode(), is(code)));
}

执行给出栈顶:

java.lang.ClassCastException: name.wilu.logic.report.utils.SheetLoader$Category$$EnhancerByCGLIB$$3a35aefc cannot be cast to net.sf.cglib.proxy.Factory
at ch.lambdaj.proxy.ClassImposterizer.createProxy(ClassImposterizer.java:134)
at ch.lambdaj.proxy.ClassImposterizer.imposterise(ClassImposterizer.java:101)
at ch.lambdaj.proxy.ProxyUtil.createProxy(ProxyUtil.java:52)
at ch.lambdaj.function.argument.ArgumentsFactory.createPlaceholder(ArgumentsFactory.java:68)
at ch.lambdaj.function.argument.ArgumentsFactory.registerNewArgument(ArgumentsFactory.java:58)
at ch.lambdaj.function.argument.ArgumentsFactory.createArgument(ArgumentsFactory.java:50)
at ch.lambdaj.function.argument.ArgumentsFactory.createArgument(ArgumentsFactory.java:39)
at ch.lambdaj.Lambda.on(Lambda.java:63)

我在使用 lambdaJ 对 hibernate 的持久集合持有实体进行操作时遇到了同样的问题。我放弃了假设已经是代理的代理对象(集合中的实体)可能存在一些问题。 看来我错了,因为类别和所有继承的类都是作为结果转换器传递给 hibernate 的 pojos。

这种行为的原因可能是什么? 你有什么想法吗?

(我使用的是最新的 lambdaj-2.4)。

添加以满足马里奥的要求

代码是一个简单的枚举。 Category 是不同类别的基类,它有代码字段。此外,它是公共(public)静态类,与所有继承类相同(如果重要的话)。

我会尝试提供失败的测试。

再次编辑以提供更多信息。 我的一个 friend 查看了代码,并对这个问题提出了新的看法。

我会尝试从头开始重现我们的演绎路径。

//给定

有一个应用程序分为两部分,第一部分 - 基础应用程序(保留模型文件)和 Web 应用程序(保留 UI 连接文件,如支持 bean 等)。 我们的类别和代码是模型类,因此位于基础应用程序中。然后我们有一个支持 bean 服务于某些 Web 逻辑,特别是那个 bean 或其合作者调用我们的选择。

//什么时候

我们正在将应用程序部署到网络服务器!在我的例子中是 JBoss。类由加载器读取,一些我不知道的非常复杂的事情发生了,所有这些都是为了让我的应用程序运行。 我做了一些网络操作,支持 bean 的方法被调用

 selectFirst(results, having(on(Category.class).getCode(), is(code)));

来自应用程序的 Web 部分。

魔术来了。 我们的 Category.class 和 Code.class 由 UnifiedClassLoader 在应用程序加载时加载。 我们在 on(Category.class) 方法中,Category 的代理将被构建。一些非常复杂的逻辑被利用来做到这一点,最重要的是,代理是用

setThreadsCallbacks(Callback[]callbacks) 

方法,但 Callback.class 是从那个类加载器中获取的

 aCategory.getClass.getClassLoader()

因此它是一个最初加载该类的类加载器,即 UnifiedClassLoader 。 干净利落地完成所有这些之后,我们终于调用了

 getFirstInstance()

使用反射浏览的Proxy类寻找: Proxy.getDeclaredMethod("setThreadsCallbacks", new Class[]{ Callback[].class });

我省略了事实,我不明白

 new Class[]{ Callback[].class }

在我们的案例中重要的是 Callback.class 不是由 UnifiedClassLoader 提供的。 应用程序在网络轮胎中执行,因此对 Callback.class 的调用将由网络应用程序服务器提供。类加载器和返回的 Callback.class 将不同于之前作为提到的 setThreadsCallbacks 函数的参数。反射残酷地失败了。

Category.class != Category.class //these two were provided by different classLoaders

这就是我无法提供失败测试的原因。 (相同的类加载器)。

我怀疑这种情况是否有任何解决方案。

最佳答案

我遇到过类似的问题。 (抛出同样的异常:java.lang.ClassCastException: XXX$Category$$EnhancerByCGLIB$$XXX cannot be cast to net.sf.cglib.proxy.Factory)

在我的例子中,结果证明是重复的(甚至是三倍的)CGLib 库的问题。我们有如下:

  • JBoss (4.2.3) 库中的cglib.jar
  • 我们应用程序网络库中的 cglib-nodep.jar(WAR 文件)
  • 应用程序网络库中的 labmdaj-2.4-with-dependencies.jar。

然后,当使用 Lambda.on(SomeClass.class) 时,我们在 CGLib 的 Enhancer 类中找到了这个方法:

private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException {
        return type.getDeclaredMethod(methodName, new Class[]{ Callback[].class });
}

其中 methodName = "CGLIB$SET_THREAD_CALLBACKS" type 是由 Enhancer 包装的 SomeClass。

“CGLIB$SET_THREAD_CALLBACKS”方法存在于包装类型中,但 getDeclaredMethod() 返回 null。似乎在 getDeclaredMethod() 内部有两个 net.sf.cglib.proxy.Callback.class 实例的比较。它们是不同的,因为一个是从 cglib.jar (JBoss) 加载的,另一个是从 cglib-nodep.jar (webapp) 加载的。

解决方案是删除多余的 cglib-nodep.jar 并将 lambda-2.4-with-dependencies.jar 替换为 lambda-2.4.jar。现在所有 CGLib 类都从公共(public)位置加载,问题已经解决。

关于java - 简单选择上的 lambdaJ 和 ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14439864/

相关文章:

java - 如何降低Android中录制的音频可视化的速度?

java - Android SQLiteAssetHelper 的 NullPointerException

java - ClassLoader:两个ClassLoader及其类之间的访问级别

java - ClassLoader:将类视为资源 - 安全还是实现细节?

java - Log4j2 配置 - 找不到 log4j2 配置文件

java - 通过 for 循环在 MapReduce 中发出中间键 - 我是否误解了 MapReduce?包括基本示例。

Java - 无法获取 MIDI 文件作为资源

java - 外部化资源适配器给出 : java. lang.ClassCastException someclass 与 someclass 不兼容

java - 如何修复 : java. lang.ClassCastException : java. util.ArrayList 无法转换为 double[]

android - 自定义 SurfaceView 上的 ClassCastException