I’m using a library called reflections. But I don’t quite know enough about what’s happening at the Java level to understand what does/should happen when calling it from Scala.
I can use the API to examine classes which I use in a Scala program, and I can use it to examine some Java classes such as java.lang.Number.
For example the following code figure out that MyNumber is a public subclass of java.lang.Number and prints the following output:
--------------
class java.lang.Number is public abstract
class genus.sanityCheck$MyNumber$1 is public
---------
class scala.collection.immutable.List is public abstract
object sanityCheck {
val refl = new org.reflections.Reflections("")
def main(argv:Array[String]):Unit = {
describeSubclasses(classOf[java.lang.Number])
makeNumber()
describeSubclasses(classOf[List[Any]])
}
def describeSubclasses(cl:Class[_]):Unit = {
import java.lang.reflect.Modifier
// getSubTypesOf does not know a class is a subclass of itself. so we use ::
val subs:List[Class[_]] = cl :: refl.getSubTypesOf(cl).toArray.toList.collect {
case c: Class[_] => c
}
println("---------")
for{ sub <- subs
} println( s"$sub is " + Modifier.toString(sub.getModifiers))
}
def makeNumber():Unit = {
class MyNumber extends Number {
def doubleValue():Double = 0.0
def longValue():Long = 0
def intValue():Int = 0
def floatValue():Float = 0.0F
}
new MyNumber
}
}
However, I can’t figure out to to get meaningful information about a class such as scala.collection.immutable.List. When I try to examine classOf[List[Any]], I find that it is also a public abstract class but has no subclasses.
Is this just a limitation of the reflections API that it is unable to find subclasses of parametrized scala classes? Or is there really something fundamentally different about List[Any] which means there can be instances of it even though it has no instantiatable subclasses?
class scala.collection.immutable.List is public abstract
class scala.collection.immutable.$colon$colon is public final
class scala.collection.immutable.Nil$ is public final
:: and Nil are indeed the only subclasses of List, according to the scaladoc.
hmm. when up update to 0.9.12 I still don’t see any subclasses of List[Any]. So it sounds like what I’m trying to do is supposed to work. Either an issue with my project setup or just a bug in the reflections library.
---------
class java.lang.Number is public abstract
class genus.sanityCheck$MyNumber$1 is public
---------
class scala.collection.immutable.List is public abstract
I wonder what could be the difference? I’ve created an issue, but I’m 99% they won’t be able to tell me anything as I don’t have enough information to reproduce the problem.
val reflect = new org.reflections.Reflections("")
assert(reflect.getSubTypesOf(classOf[List[Any]]).toArray.contains(List(1,2,3).getClass))
assert(reflect.getSubTypesOf(classOf[List[Any]]).toArray.contains(List.empty.getClass))
So, I commented the plugin in project/plugins.sbt and removed the dependency on scastie’s scala-runtime. Also, wrapped the code in main.scala into an object extending App.
java.lang.AssertionError: assertion failed
at scala.Predef$.assert(Predef.scala:265)
at Playground$.delayedEndpoint$Playground$1(main.scala:10)
at Playground$delayedInit$body.apply(main.scala:2)
at scala.Function0.apply$mcV$sp(Function0.scala:39)
at scala.Function0.apply$mcV$sp$(Function0.scala:39)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
at scala.App.$anonfun$main$1(App.scala:76)
at scala.App.$anonfun$main$1$adapted(App.scala:76)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:563)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:561)
at scala.collection.AbstractIterable.foreach(Iterable.scala:919)
at scala.App.main(App.scala:76)
at scala.App.main$(App.scala:74)
at Playground$.main(main.scala:2)
at Main$.main(main.scala:24)
at Main.main(main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sbt.Run.invokeMain(Run.scala:133)
at sbt.Run.execute$1(Run.scala:82)
at sbt.Run.$anonfun$runWithLoader$5(Run.scala:110)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:17)
at sbt.TrapExit$App.run(TrapExit.scala:258)
at java.lang.Thread.run(Thread.java:748)
And it also fails in scastie for me. That’s why I wanted to try it locally; it’s a pity one cannot reproduce problems with scastie since they are using dependencies sbt cannot resolve…
But, what happens if you download the scastie example and comment out the two lines I mentioned and make the example a runnable application… Does it work for you then @jimka ?