Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong number of arguments invoking a Scala constructor using reflection

I'm trying to invoke the newInstance method of a constructor of a Scala class (case class or usual class, both are affected).

However, I'm running into a IllegalArgumentException with the hint wrong number of arguments.

Consider the following:

case class Vec2(x: Float, y: Float)

object TestApp {
  def main(args: Array[String]) {
    //after some research I found the last constructor always to be the default
    val ctor = classOf[Vec2].getConstructors.last

    println("ctor = " + ctor)
    println("takes parameters: " + ctor.getParameterTypes.length)

    val params = new Array[Float](2)

    params.update(0, 1.0f)
    params.update(1, -1.0f)

    println("num parameters: " + params.length)

    println("trying to create new instance...")
    try {
      val x = ctor.newInstance(params)
      println("new instance: " + x)
    }
    catch {
      case ex => ex.printStackTrace
    }
  }

The output is as follows:

ctor = public pd.test.Vec2(float,float)
takes parameters: 2
num parameters: 2
trying to create new instance...
java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at pd.test.TestApp$.main(TestApp.scala:60)
    at pd.test.TestApp.main(TestApp.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:115)

I have experienced something like this in Java once. In that case the class I was trying to instantiate was an inner class of another class, so Java expected an implicit additional parameter, which was either the Class object of the enclosing class (if the class was declared as static), or an instance of the enclosing class.

However, in this case there is no enclosing class of Vec2, unless Scala adds one internally (though, java.lang.Class.getEnclosingClass() returns null for me).

So my question is how to instantiate Scala classes using reflection? Are there any additional parameters Scala constructors expect implicitly?

like image 881
pdinklag Avatar asked Feb 02 '11 07:02

pdinklag


1 Answers

The newInstance method takes a varargs parameter. In Scala (unlike Java), you can't just pass an array and have it automatically treated as all the arguments. If that's what you want you need to do it explicitly like this:

ctor.newInstance(params:_*)

What you're doing at the moment is passing an array with 2 elements as the first argument to the constructor.

like image 77
Ben Lings Avatar answered Sep 30 '22 16:09

Ben Lings