java.lang.NoClassDefFoundError since 2016.2 update Follow
Hello,
i'm trying to add java 8 support to following plugin https://github.com/bobi/felix-annotation-processor
but since idea 2016.2 i'm receiving java.lang.NoClassDefFoundError, on previous versions it works.
full stack trace:
org.jetbrains.jps.incremental.ProjectBuildException: Module 'felix-test' production: java.lang.NoClassDefFoundError: org/slf4j/spi/LoggerFactoryBinder
at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:1012)
at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:870)
at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:696)
at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:387)
at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:194)
at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:138)
at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:294)
at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:125)
at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler$1.run(BuildMain.java:232)
at org.jetbrains.jps.service.impl.SharedThreadPoolImpl$1.run(SharedThreadPoolImpl.java:44)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: org/slf4j/spi/LoggerFactoryBinder
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:411)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:142)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:121)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:332)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:284)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:305)
at foo.bar.Test.<clinit>(Test.java:19)
at sun.misc.Unsafe.ensureClassInitialized(Native Method)
at sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAccessorFactory.java:43)
at sun.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:142)
at java.lang.reflect.Field.acquireFieldAccessor(Field.java:1088)
at java.lang.reflect.Field.getFieldAccessor(Field.java:1069)
at java.lang.reflect.Field.get(Field.java:393)
at org.apache.felix.scrplugin.annotations.FieldAnnotation.getAnnotatedFieldValue(FieldAnnotation.java:60)
at org.apache.felix.scrplugin.processing.SCRAnnotationProcessor.createProperties(SCRAnnotationProcessor.java:407)
at org.apache.felix.scrplugin.processing.SCRAnnotationProcessor.process(SCRAnnotationProcessor.java:174)
at org.apache.felix.scrplugin.helper.AnnotationProcessorManager.process(AnnotationProcessorManager.java:94)
at org.apache.felix.scrplugin.helper.ClassScanner.processClass(ClassScanner.java:213)
at org.apache.felix.scrplugin.helper.ClassScanner.process(ClassScanner.java:161)
at org.apache.felix.scrplugin.helper.ClassScanner.scanSources(ClassScanner.java:146)
at org.apache.felix.scrplugin.SCRDescriptorGenerator.execute(SCRDescriptorGenerator.java:146)
at net.chilicat.felixscr.intellij.build.scr.AbstractScrProcessor.execute(AbstractScrProcessor.java:77)
at net.chilicat.felixscr.intellij.jps.FelixModuleLevelBuilder.build(FelixModuleLevelBuilder.java:43)
at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1237)
at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:911)
at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:983)
... 14 more
Caused by: java.lang.ClassNotFoundException: org.slf4j.spi.LoggerFactoryBinder
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
Please sign in to leave a comment.
Hi Andrey,
Please note the "Caused by:...." stacktrace part.
It looks lilke net.chilicat.felixscr.intellij.jps.FelixModuleLevelBuilder creates an instance ScrProcessor and configures it with some classpath. The ScrProcessor then creates a classloader for the specified classpath, loads classes with this classLoader and processes loaded classes via Reflection API.
This particular exception is caused by the incomplete classpath that ScrProcessor prepared.
Hope this helps,
Best regards,
Eugene.
Hi, classpath looks ok, also same code works on idea 2016.1.4 but does not work on idea 2016.2 and newer.
in general classpath and classloader looks the following
final Collection<String> classPath = new LinkedHashSet<String>();
classPath.add(moduleChunk.representativeTarget().getOutputDir());
classPath.add(PathUtil.getJarPathForClass(Component.class));
classPath.add(PathUtil.getJarPathForClass(BundleContext.class));
JpsJavaExtensionService service = JpsJavaExtensionService.getInstance();
JpsJavaDependenciesEnumerator enr = service.enumerateDependencies(Collections.singleton(moduleChunk.representativeTarget().getModule()));
JpsJavaDependenciesRootsEnumerator classes = enr.productionOnly().withoutSdk().recursively().classes();
for (File f : classes.getRoots()) {
// filter out non-Java classpath entries, because Felix fails processing them
if (f.getName().endsWith(".class") || f.getName().endsWith(".jar") || f.isDirectory()) {
classPath.add(f.getAbsolutePath());
}
}
final URL[] urls = new URL[classPath.size()];
for (int i = 0; i < classPath.size(); i++) {
urls[i] = new File(classPath.get(i)).toURI().toURL();
}
ClassLoader classloader = new URLClassLoader(urls, this.getClass().getClassLoader());
> looks ok, also same code works on idea 2016.1.4 but does not work on idea 2016.2 and newer.
Such behavior is quite possible. Take a look at how the classloader is created:
new URLClassLoader(urls, this.getClass().getClassLoader());
Parent classloader is not null and is the same loader that loaded the ScrProcessor. This means that created loader will first try to resolve classes against JPS classes and only then against the specified classpath urls.
Previous versions of IDEA might have had this missing class in the classpath, while the newer builds don't. There is also no guarantee that newer versions of JPS won't be using classes or libraries that would conflict with the classes present in the user's project being compiled.
Strictly speaking, using classloader in compiler for compiled project's class resolution is the easiest, but not the best approach, mainly because classes are loaded in compiler's JVM and compiler's environment influences the resolution result a lot. This case is a good example of such problems.
You can make class resolution process less dependent on builder's runtime, if you pass null to the classloader, but still there might be problems with cross-compilation:
- bytecode version of user's classes may be incompatible with builder's runtime;
- in general case there is no way to resolve JDK classes against the JDK that is specified in project configuration: with classloader-based approach system classes will always be resolved against the JDK that is used to run the JPS build system.
Thank you, make sense for me, but....
I need parent classloader as i need to pass log messages from SCR Generator to Idea messages window.
also i found the issue, org.slf4j.impl.StaticLoggerBinder was included into gradle plugin but slf4j was not in parent classpath.
> I need parent classloader as i need to pass log messages from SCR Generator to Idea messages window.
I would still re-consider using classloaders for user's code analysis.Sooner or later the problems I mentioned above will appear. The ASM bytecode analysis framework looks like a great choice for the task.