LambdaJ and ClassCastException on simple selection

I ran out of ideas, Google didn't help either. The use case seems trivial, but it fails with a ClassCastException. I don't know what I am doing wrong. There's a simple method for returning the first item that matches a given category, take a look.

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

      

Execution gives this top of the stack:

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)

      

I had the same problem when I used lambdaJ to manipulate hibernate storage entities. I gave up on the assumption that there might be a problem with proxy objects (entities in a collection) that are already proxies. I seem to be wrong because Category and all inherited classes are pojos, passed to hibernate as a result transformer.

What could be the reason for this behavior? Do you have any ideas?

(I am using the latest lambdaj-2.4).

Added to fulfill Mario's request

The code is a simple enumeration. Category is the base class for different categories, it has a code field. Moreover, it is a public static class, the same as all inheriting classes (if it matters).

I will try to provide an error test.

Editing again to provide more information. My friend took a look at the code and freshened up the light.

I will try to reproduce our path of deduction from the very beginning.

//Considering

There, the application is split into two parts: a first base application (stores model files) and a web application (supports files with a connected interface like supporting beans, etc.). Our category and code are model classes, so they are located in the base application. We have bean support serving some web logic and especially which bean or its co-authors calls our choice.

//When

We are deploying the application to a web server! JBoss in my case. The classes are read by loaders, some pretty tricky things that I don't know about, all to get my application to work. I am using web action and that bean method called bean is called

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

      

from the application web part.

This is where magic comes in. Our Category.class and Code.class were loaded by the UnifiedClassLoader when loading the app. We are in on (Category.class) and the Category proxy will be created. Some really convoluted logic is used to do this, most importantly a proxy tool using

setThreadsCallbacks(Callback[]callbacks) 

      

but the Callback.class is taken from this classloader

 aCategory.getClass.getClassLoader()

      

thus, it is the classloader that originally loaded this class, UnifiedClassLoader. After all this has been done cleanly, we finally call

 getFirstInstance()

      

using reflective views. The proxy class is looking for: Proxy.getDeclaredMethod ("setThreadsCallbacks", new class [] {Callback []. Class});

I'm omitting the fact, I don't understand

 new Class[]{ Callback[].class }

      

What's important in our case is that Callback.class IS NOT SUPPLIED BY UnifiedClassLoader. Applicaiton runs on the network bus, so calling Callback.class will be the server through the web application. the loader class and the saved Callback.class will be dffer from what was previously supplied as a segment for the mentioned setThreadsCallbacks functionality. Reflection fails.

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

      

This is why I was unable to fail the test. (same classloader).

I doubt there is any solution in this case.

+3


source to share


1 answer


I faced a similar problem. (Same exception thrown: java.lang.ClassCastException: XXX $ Category $$ EnhancerByCGLIB $$ XXX cannot be traced to net.sf.cglib.proxy.Factory)

In my case it turned out to be a problem with the duplicated (or even tripled) CGLib. We had the following:

  • cglib.jar in JBoss library (4.2.3)
  • cglib-nodep.jar in our web application library (WAR file)
  • labmdaj-2.4-with-dependencies.jar in the web application library.

Then, using Lambda.on (SomeClass.class), we get this method in the CGLib Enhancer

class:



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

      

where methodName = "CGLIB$SET_THREAD_CALLBACKS"

u enter our SomeClass wrapped in Enhancer

.

The "CGLIB $ SET_THREAD_CALLBACKS" method was present in the wrapped type, but getDeclaredMethod () returned null. It turned out that inside getDeclaredMethod () there was a mapping of two instances net.sf.cglib.proxy.Callback.class

. And they were different as one was loaded from cglib.jar (JBoss) and the other from cglib-nodep.jar (webapp).

The solution was to remove the redundant cglib-nodep.jar and replace lambda-2.4-with-dependencies.jar with lambda-2.4.jar. Now all CGLib classes are loaded from common place and the problems are gone.

+1


source







All Articles