Scala/java reflection - `newInstance` throws InstantiationException

Viewed 860
object classof extends App {

 trait Config {
    def test(): Unit
  }

  case class Test() extends Config {
    override def test(): Unit = println("test")
  }

  val s = classOf[Test]

  s.newInstance().test()

}

The above code works fine, but when you run it as a scala worksheet, it throws InstantiationException.

Caused by: java.lang.NoSuchMethodException: 
reflection.A$A20$A$A20$Test.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)

I am facing this issue primarily when executing tests. For example

Animal.config.newInstance().test where Animal is an instantiated object and config holds val config: Class[_ <: Config] = classOf[Test].

I don't have sound knowledge on java reflections. Not sure why this is happening.

2 Answers

I run your example first in IntelliJ idea with a ScalaWorkSheet, and I felt into your same error, my conclusion is that reflection is not well implemented in scala sheet, for me the log is:

(I tried different ways expecting different results):

trait Config {
  def test(): Unit
}

case class Test() extends Config {
  override def test(): Unit = println("test")
}

Test.getClass.getSimpleName

val t: Test = classOf[Test].getConstructors()(0).newInstance().asInstanceOf[Test]

t.test()

java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(TestingSO.sc)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(TestingSO.sc:58)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(TestingSO.sc:41)
    at java.lang.reflect.Constructor.newInstance(TestingSO.sc:419)
...

The most rare thing is:

sun.reflect.NativeConstructorAccessorImpl.newInstance0(TestingSO.sc)

That's the name of my scala

Then I made a simple scala class:

class Testing {
}

trait Config {
  def test(): Unit
}

case class Test() extends Config {
  override def test(): Unit = println("test")
}

object Main{
  def main(args: Array[String]): Unit = {
    val s = classOf[Test]

    s.newInstance().test()
  }
}

And works just fine...

Conclusion

Careful with Scala Sheet, some times may be a sh*t haha

Note the A$A20$A$A20$Test name. It hints that this is really an inner class (worksheets have to wrap code into a class/object because Scala doesn't support top-level code directly; you'll see the same in the REPL).

And inner classes require an instance of the outer class to construct. So there is no constructor without parameters and simply calling newInstance() can't work.

Related