我无计可施,谷歌也没帮上忙。用例似乎是微不足道的,但它失败与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类都是从公共位置加载的,问题已经解决了。