Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scan with Scala library in classpath gives error about different superclasses #193

Closed
ryan-gustafson opened this issue Apr 26, 2018 · 7 comments

Comments

@ryan-gustafson
Copy link

See the attached fast-classpath-scanner-scala.tar.gz file containing a Gradle project which runs a test attempting to scan with the Scala library version 2.12.4 in the classpath.

The archive includes a verbose.log file from my local run (on a Mac). The exception message is:

Caused by: java.lang.IllegalArgumentException: A class and its auxiliary class have different superclasses: class extends scala.collection.generic.SeqFactory<scala.collection.immutable.Stack> implements scala.Serializable ; <A> class extends scala.collection.AbstractSeq<A> implements scala.collection.immutable.LinearSeq<A>, scala.collection.LinearSeqOptimized<A, scala.collection.immutable.Stack<A>>, scala.Serializable

You should be able to run yourself using:

tar xvfz fast-classpath-scanner-scala.tar.gz
cd fast-classpath-scanner-scala
./gradlew build

The test sends System.out/System.err to the verbose.log file.

For now, I'll try to work around the issue by determining how to exclude certain packages or files from scanning.

@lukehutch
Copy link
Member

Thanks @ryan-gustafson for reporting this, and especially for attaching a testcase! I'll try to incorporate this case into an FCS testcase soon, unless you have a chance to do that yourself.

This exception was thrown precisely to get this sort of bug report filed if anyone ever came across the Scala compiler doing something as egregious as this! (At least, egregious from the point of view of Java's single inheritance model...)

FCS already has ClassInfo#getNameOfSuperclass(), which usually returns exactly one superclass, and will throw an exception if there is more than one superclass, and ClassInfo#getNameOfSuperclasses(), which in this case would return two superclasses: scala.collection.generic.SeqFactory<scala.collection.immutable.Stack> and scala.collection.AbstractSeq<A>. (FCS combines classes and their auxillary classes, as generated by the Scala compiler from a single source class, into a single ClassInfo object.)

However, the code never got that far, because I inserted code to throw the exception you are seeing. The reason for the exception is really to have the chance to ask a Scala developer: is it sane in this case to report two superclasses of this class? Or should this information be delivered to the developer in some other way in the FCS API? (Sorry, the exception message text is incomplete, in that it doesn't name the class in question, or its auxillary class.)

Or is it better not to combine classes and their auxillary classes into a single ClassInfo object?

@ryan-gustafson
Copy link
Author

Sorry I didn't look close enough to understand how to setup an FCS testcase for this, so I figured I'd at least give you something to reproduce the problem.

Unfortunately, I know nothing about scala that would help here, I merely encountered this when trying to scan an existing extensive classpath. You might need to reach out to the scala devs, it seems like a pretty central library.

For my usage, I was able to proceed using the comments from #190.

@lukehutch
Copy link
Member

For reference, from the Scala source: https://github.com/scala/scala/blob/2.12.x/src/library/scala/collection/immutable/Stack.scala

object Stack extends SeqFactory[Stack] {
  /** $genericCanBuildFromInfo */
  implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Stack[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
  def newBuilder[A]: Builder[A, Stack[A]] = new ArrayBuffer[A] mapResult (buf => new Stack(buf.toList))
}

class Stack[+A] protected (protected val elems: List[A])
                 extends AbstractSeq[A]
                    with LinearSeq[A]
                    with GenericTraversableTemplate[A, Stack]
                    with LinearSeqOptimized[A, Stack[A]]
                    with Serializable {
  override def companion: GenericCompanion[Stack] = Stack
  // ...
}

So the object and class definitions extend different classes. I wonder how common this is?

@lukehutch
Copy link
Member

From https://stackoverflow.com/a/1755521/3950982 :

if there is a class C, then object C is the companion object of class C; note that the companion object is not automatically an instance of C.

Given that, maybe the right thing to do is not try to merge Scala companion classes (ending with $ or $class) into the base class.

@pshirshov
Copy link

I second this. Very annoying thing.
Though thanks for the library.

@lukehutch
Copy link
Member

@ryan-gustafson @pshirshov this is fixed in 2.19.0.

You will now get pkg.Class for a base class in Scala, pkg.Class$ for a companion object, and pkg.Class$class for a trait methods class (i.e. these are no longer merged into pkg.Class).

@lukehutch
Copy link
Member

@ryan-gustafson I just pushed out version 2.20.1, with support for explicitly blacklisting classpath elements based on a string match criterion:

https://github.com/lukehutch/fast-classpath-scanner/releases/tag/fast-classpath-scanner-2.20.1

This will work better than the code snippet I gave in #190, since it applies the filtering before extracting jars-within-jars (in the case that you have classpath elements like path/to/jar1.jar!/BOOT-INF/lib/jar2.jar).

(However, hopefully you don't need to skip directories now that Scala scanning is fixed.)

bradfordboyle added a commit to bradfordboyle/geode that referenced this issue May 10, 2018
fast-classpath-scanner has a [known issue][0] scanning when the classpath
contains Scala library. This has been fixed in version 2.19.0.

Updating the version of fast-classpath-scanner allows deploying JARs
that contain the Scala library (i.e., fat JARs).

[0]: classgraph/classgraph#193
jdeppe-pivotal pushed a commit to apache/geode that referenced this issue May 15, 2018
fast-classpath-scanner has a [known issue][0] scanning when the classpath
contains Scala library. This has been fixed in version 2.19.0.

Updating the version of fast-classpath-scanner allows deploying JARs
that contain the Scala library (i.e., fat JARs).

[0]: classgraph/classgraph#193
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants