lambdaJ和ClassCastException在简单的选择



我无计可施,谷歌也没帮上忙。用例似乎是微不足道的,但它失败与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)。

添加以满足马里奥的请求

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

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

再次编辑以提供额外信息。我的一个朋友看了一下代码,对这个问题有了新的认识。

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

//给

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

//

我们正在将应用程序部署到web服务器!对我来说是老板。类是由加载器读取的,一些我不知道的非常复杂的事情发生了,所有这些都是为了让我的应用程序运行。我做一些web操作,然后支持bean的方法被称为

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

from web part of application.

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

setThreadsCallbacks(Callback[]callbacks) 

方法,但Callback.class是从该类装入器中获取的

 aCategory.getClass.getClassLoader()

因此它是一个类加载器,最初加载了这个类,即UnifiedClassLoader。完成所有这些之后,我们最终调用

 getFirstInstance()

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

我省略了事实,我不明白

 new Class[]{ Callback[].class }

在我们的例子中重要的是Callback.class不是由UnifiedClassLoader提供的。应用程序是在web环境中执行的,所以Callback.class的调用将由web app. class加载器在服务器端执行,并且返回的Callback.class将不同于之前作为提到的setThreadsCallbacks函数的参数。反射严重失败

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

这就是为什么我不能提供失败的测试。(相同的类加载器).

我怀疑这种情况没有解决办法。

我也遇到过类似的问题。(抛出的相同异常:java.lang.ClassCastException: XXX$Category$$EnhancerByCGLIB$$XXX不能强制转换为net.sf.cglib.proxy.Factory)

在我的情况下,它原来是一个问题与重复(甚至三倍)CGLib库。我们有如下文件:

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

然后,当使用Lambda.on(somecclass .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"的地方和类型是我们用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类都是从公共位置加载的,问题已经解决了。

相关内容

  • 没有找到相关文章

最新更新