【问题标题】:lambdaJ and ClassCastException on simple select简单选择上的 lambdaJ 和 ClassCastException
【发布时间】:2013-02-04 20:17:13
【问题描述】:

我的想法用完了,谷歌也没有帮助。用例似乎微不足道,但因 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 的持久集合进行操作时遇到了同样的问题。我放弃了假设已经是代理的代理对象(集合中的实体)可能存在一些问题。 看来我错了,因为 Category 和所有继承的类都是 pojos 作为结果转换器传递给休眠的。

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

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

添加以满足马里奥的要求

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

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

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

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

// 给定

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

// 何时

我们正在将应用程序部署到 Web 服务器!就我而言,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.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 classloader classcastexception cglib lambdaj


    【解决方案1】:

    我也遇到过类似的问题。 (同样抛出异常: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 类都是从公共位置加载的,问题已经解决了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-30
      • 2020-02-08
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多