-
Notifications
You must be signed in to change notification settings - Fork 83
Description
TL;DR: It should be possible to force Platfom.getClassLoader(Class<?>) to prefer the classloader of the class over the context classloader of the thread.
Details: I am running JavaCL in an OSGi bundle (a plugin for a GUI application called Cytoscape). The plugin provides methods that are executed on threads created by the application framework. I try to call kernels from the application-created thread, which results in some class loading for event callbacks with CallbackNativeImplementer. But that throws NoClassDefFoundError (stacktrace below).
After some funny debugging, I realized that the problem is that the parent classloader of CallbackNativeImplementer is NOT the bundle classloader - it is the classloader returned by Platfom.getClassLoader() (set in the constructor of CallbackNativeImplementer). And Platfom.getClassLoader() first checks Thread.currentThread().getContextClassLoader() which returns the class loader of the application framework, which does not see the bundle resources.
As a workaround, I use Thread.currentThread().setContextClassLoader() to set the correct class loader before invoking any JavaCL methods, but that seems hacky. I am not sure for what use cases the context classloader is more appropriate than the classloader of the active class, but maybe there could be some setting to give preference to the class's classloader over the thread...
Or is there some other way to enforce proper classloader in this case?
I'll be happy to work on this issue once someone from the team confirms what is the correct way to address it.
Note that I am not using the OSGi version of JavaCL, instead, I embed the JavaCL jars within my bundle (with directive of Maven bundle plugin) as this is mandated by the Cytoscape plugin development rules.
I however think that the problem would arise the same if JavaCL was used as an OSGi bundle (the calling thread would still provide different class loader).
I did some tests with having JavaCL as a separete bundle and the problem did not go away, although I am not certain I did everything well.
The promised stacktrace:
Caused by: java.lang.NoClassDefFoundError: com/nativelibs4java/opencl/library/IOpenCLLibrary$clSetEventCallback_arg1_callback
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at org.bridj.CallbackNativeImplementer.defineClass(CallbackNativeImplementer.java:214)
at org.bridj.CallbackNativeImplementer.getCallbackImplType(CallbackNativeImplementer.java:103)
at org.bridj.CRuntime.register(CRuntime.java:426)
at org.bridj.CRuntime.registerFamily(CRuntime.java:483)
at org.bridj.CRuntime.register(CRuntime.java:470)
at org.bridj.CRuntime.register(CRuntime.java:345)
at org.bridj.CRuntime$CTypeInfo.<init>(CRuntime.java:126)
at org.bridj.CRuntime.getTypeInfo(CRuntime.java:336)
at org.bridj.BridJ.getTypeInfo(BridJ.java:377)
at org.bridj.BridJ.initialize(BridJ.java:1126)
at org.bridj.NativeObject.<init>(NativeObject.java:50)
at org.bridj.Callback.<init>(Callback.java:60)
at com.nativelibs4java.opencl.library.IOpenCLLibrary$clSetEventCallback_arg1_callback.<init>(IOpenCLLibrary.java:576)
at com.nativelibs4java.opencl.CLEvent$3.<init>(CLEvent.java:128)
at com.nativelibs4java.opencl.CLEvent.<clinit>(CLEvent.java:128)
at com.nativelibs4java.opencl.CLKernel.enqueueNDRange(CLKernel.java:482)
at cz.cas.mbu.gn.compute.GNCompute.executeKernel(GNCompute.java:121)
at cz.cas.mbu.gn.compute.GNCompute.computeAdditiveRegulation(GNCompute.java:342)
at cz.cas.mbu.cygngpu.internal.PredictSingleRegulationsTask.run(PredictSingleRegulationsTask.java:176)
at org.cytoscape.work.internal.task.JDialogTaskManager$TaskRunnable.innerRun(JDialogTaskManager.java:326)
at org.cytoscape.work.internal.task.JDialogTaskManager$TaskRunnable.run(JDialogTaskManager.java:355)
... 5 more
Caused by: java.lang.ClassNotFoundException: com.nativelibs4java.opencl.library.IOpenCLLibrary$clSetEventCallback_arg1_callback
at java.lang.ClassLoader.findClass(ClassLoader.java:530)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 29 more