bmc / classutil

Scala-friendly, fast class-finder library (using ASM under the covers)
http://software.clapper.org/classutil/
Other
94 stars 29 forks source link

java.lang.IncompatibleClassChangeError upon invoking getClasses() on ClassFinder instance #19

Open chipsenkbeil opened 9 years ago

chipsenkbeil commented 9 years ago

Hi there! Was checking out the library, which looks really nice. I added the dependency through Maven Central (using sbt 0.13.7) via libraryDependencies += "org.clapper" %% "classutil" % "1.0.5", so not sure if that would be an issue since the instructions reference bin-tray. I'm compiling with Scala 2.10.4, by the way.

Anyway, I seem to have encountered an exception when invoking mainClassFinder.getClasses() where mainClassFinder is a ClassFinder instance that is using the current classpath. I'm not sure if this is a problem from me adding the dependency from Maven central - FYI, I tried bin-tray afterwards with same result - or if it's an issue with my classpath or something else. Any guidance?

Code

import java.io.File
import org.clapper.classutil.{ClassInfo, ClassFinder}

class ModuleManager(extraClassPaths: Seq[String] = Nil) {
  private lazy val mainClassFinder: ClassFinder = ClassFinder()
  private lazy val extraClassFinder: Option[ClassFinder] = Option(
    if (extraClassPaths.nonEmpty) ClassFinder(extraClassPaths.map(new File(_)))
    else null
  )

  private lazy val allClasses = mainClassFinder.getClasses() ++
    extraClassFinder.map(_.getClasses()).getOrElse(Stream.empty[ClassInfo])
  private lazy val allClassMap =
    ClassFinder.classInfoMap(allClasses.toIterator)

  lazy val modules = ClassFinder.concreteSubclasses(
    classOf[ModuleLike].getName,
    allClassMap
  )

  modules.foreach(println)
}

Exception

Exception in thread "main" java.lang.IncompatibleClassChangeError: class org.clapper.classutil.asm.EmptyVisitor has interface org.objectweb.asm.ClassVisitor as super class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at org.clapper.classutil.asm.ClassFile$.load(ClassFinderImpl.scala:190)
    at org.clapper.classutil.ClassFinder.org$clapper$classutil$ClassFinder$$classData(ClassFinder.scala:406)
    at org.clapper.classutil.ClassFinder$$anonfun$2.apply(ClassFinder.scala:364)
    at org.clapper.classutil.ClassFinder$$anonfun$2.apply(ClassFinder.scala:364)
    at scala.collection.immutable.Stream.map(Stream.scala:376)
    at org.clapper.classutil.ClassFinder.processOpenZip(ClassFinder.scala:364)
    at org.clapper.classutil.ClassFinder.processJar(ClassFinder.scala:318)
    at org.clapper.classutil.ClassFinder.findClassesIn(ClassFinder.scala:307)
    at org.clapper.classutil.ClassFinder.find(ClassFinder.scala:299)
    at org.clapper.classutil.ClassFinder.getClasses(ClassFinder.scala:289)
    at com.ibm.spark.kernel.module.ModuleManager.allClasses$lzycompute(ModuleManager.scala:37)
    at com.ibm.spark.kernel.module.ModuleManager.allClasses(ModuleManager.scala:37)
    at com.ibm.spark.kernel.module.ModuleManager.allClassMap$lzycompute(ModuleManager.scala:40)
    at com.ibm.spark.kernel.module.ModuleManager.allClassMap(ModuleManager.scala:39)
    at com.ibm.spark.kernel.module.ModuleManager.modules$lzycompute(ModuleManager.scala:45)
    at com.ibm.spark.kernel.module.ModuleManager.modules(ModuleManager.scala:42)
    at com.ibm.spark.kernel.module.ModuleManager.<init>(ModuleManager.scala:48)
chipsenkbeil commented 9 years ago

FYI, using version 1.0.3 pulled from Maven central works for me, so I'm not sure what has changed since then.

chipsenkbeil commented 8 years ago

FYI, using 1.0.6, this still happens when I try to invoke the method while running in ScalaTest. Running it as part of a normal program seems to work fine.

Reverting to 1.0.3 still resolves this issue for me.

chipsenkbeil commented 8 years ago

@bmc, this seems related to the addition of the EmptyVisitor class and the move to ASM4. I had forgotten about this issue with a fresh project until I was trying to run integration tests using classutil and hit this issue. Any idea what is happening here? Class incompatibilities are normally from binary incompatibilities when you haven't recompiled after something changed, but I've been hitting this in ScalaTest with a clean build.

Calling ClassFinder().getClasses inside ScalaTest is dying for me.

bmc commented 8 years ago

I've run across this one myself. I'm trying to reproduce it reliably so I can figure out what it is.

bmc commented 8 years ago

I've just released version 1.0.9, which includes an ASM version bump to 5.1. Can you still reproduce the problem with 1.0.9?

I'm not closing this bug yet...

rakeshh commented 8 years ago

I am also facing this issue. It runs fine on local machine, but when i run it on cluster(as part of some other job) it is throwing this exception.

rakeshh commented 8 years ago

I am getting this error with versions 1.0.9 and 1.0.10 .

anuragranjan108 commented 8 years ago

I'm getting this issue with 1.0.10 still.

anuragranjan108 commented 8 years ago

@bmc This is still breaking on 1.0.11

bmc commented 8 years ago

I confess that I'm having trouble reproducing this error. If you're still having this problem, please post additional details, such as:

Thanks.

whitebearded commented 8 years ago

Hi there! I can confirm that issue using <artifactId>classutil_2.11</artifactId><version>1.0.11</version>.

Error when execing val classes = finder.getClasses: java.lang.IncompatibleClassChangeError: class org.clapper.classutil.asm.ASMEmptyVisitor has interface org.objectweb.asm.ClassVisitor as super class at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:760) 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 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:760) 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 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.clapper.classutil.asm.ClassFile$.load(ClassFinderImpl.scala:250) at org.clapper.classutil.ClassFinder.org$clapper$classutil$ClassFinder$$classData(ClassFinder.scala:427) at org.clapper.classutil.ClassFinder$$anonfun$5.apply(ClassFinder.scala:411) at org.clapper.classutil.ClassFinder$$anonfun$5.apply(ClassFinder.scala:409) at scala.collection.immutable.Stream.map(Stream.scala:418) at org.clapper.classutil.ClassFinder.processDirectory(ClassFinder.scala:409) at org.clapper.classutil.ClassFinder.findClassesIn(ClassFinder.scala:333) at org.clapper.classutil.ClassFinder.find(ClassFinder.scala:320) at org.clapper.classutil.ClassFinder.getClasses(ClassFinder.scala:311)

instanceofme commented 7 years ago

This issue seems caused by the presence of ASM 3.x in the classpath, causing a conflict. In this earlier version, ClassVisitor was an interface instead of an abstract class.

The common way to go seems to be shadowing asm, relocating its package to something like org.clapper.classutil.shadow.asm. Do you think that would be possible here?

bmc commented 7 years ago

I'll try that. Thanks.

instanceofme commented 7 years ago

I confirm that this solved at least my instance of this issue. Used jar jar links to relocate inside an assembly (fat / consolidated) jar that had a dependency on classutil, worked like a charm.

bmc commented 7 years ago

I'm not sure (yet) whether I want to shadow ASM in the official released classutil jar, but I can at least provide documentation on getting around the problem. Thanks.