This page is no longer maintained — Please continue to the home page at www.scala-lang.org

2.8.0.h: constructor, default parameter value and reflection

1 reply
richard emberson
Joined: 2010-03-22,
User offline. Last seen 42 years 45 weeks ago.

I'd like to create an instance using reflection. The
class has a single constructor which takes a parameter
which has a default value. How do I get to the correct
constructor in Scala?
Below is a test class which has one class with with two
constructors - and this one reflection works on. And
a second class which has a single constructor which
has a default value - and this one I can figure out how
to get a handle on so I can create an instance.

File Test.scala

import java.lang.reflect.Constructor

object Util {

val EMPTY_CLASS_ARRAY = Array[Class[_]]()
val EMPTY_OBJECT_ARRAY = Array[Any]()

}

class Builder[T](interfaceClass: Class[T]) {
def lookupClass(name: String) : Class[_ <: T] = {
var clz = Class.forName(name)
clz.asSubclass(interfaceClass)
}

def getConstructor(clz: Class[_ <: T],
parameterTypes: Array[Class[_]]): Constructor[_ <:
T] = {
clz.getConstructor(parameterTypes: _*)
}

def newInstance(constructor: Constructor[_ <: T],
parameterValues: Array[Any]): T = {
constructor.newInstance(parameterValues.map(_.asInstanceOf[AnyRef])
: _*)
}
}

class Works(name: String) {
def this() = this("Works")

def getName: String = name
}

class DoesNotWork(name: String = "DoesNotWork") {
def getName: String = name
}

import Util._

object Main {
def doWorks {
val builder = new Builder[Works](classOf[Works])
var clz: Class[_ <: Works] = builder.lookupClass("Works")
var constructor = builder.getConstructor(clz, EMPTY_CLASS_ARRAY)
var works: Works = builder.newInstance(constructor, EMPTY_OBJECT_ARRAY)
println("name="+works.getName)
}
def doesNotWork {
val builder = new Builder[DoesNotWork](classOf[DoesNotWork])
var clz: Class[_ <: DoesNotWork] = builder.lookupClass("DoesNotWork")
var constructor = builder.getConstructor(clz, EMPTY_CLASS_ARRAY)
var notworks: DoesNotWork = builder.newInstance(constructor,
EMPTY_OBJECT_ARRAY)
println("name="+notworks.getName)
}
def usage {
println("Enter either: \"works\" or \"doesnotworks\"")
}
def main(args: Array[String]) {
args match {
case Array("works") => doWorks
case Array("doesnotwork") => doesNotWork
case _ => usage
}

}
}

> scalac Test.scala
> scala Main
Enter either: "works" or "doesnotwork"
> scala Main works
name=Works
> scala Main doesnotwork
java.lang.NoSuchMethodException: DoesNotWork.()
at java.lang.Class.getConstructor0(Class.java:2706)
at java.lang.Class.getConstructor(Class.java:1657)
at Builder.getConstructor(Works.scala:19)
at Main$.doesNotWork(Works.scala:51)
at Main$.main(Works.scala:61)
at Main.main(Works.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
scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:55)
at
scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:22)
at
scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:61)
at
scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:55)
at
scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:61)
at
scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:153)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

Using reflection how can I tell if a class has constructors that
have default parameters and how can I call the one that will
build an instance using the default value.

Thanks
Richard

rytz
Joined: 2008-07-01,
User offline. Last seen 45 weeks 5 days ago.
Re: 2.8.0.h: constructor, default parameter value and reflecti
use javap to look at the decompiled version of
class DoesNotWork(name: String = "DoesNotWork") {
 def getName: String = name
}
this class has no parameterless constructor in bytecode. if you want
to use the default argument you have to call the method

  DoesNotWork$.MODULE$.init$default$1

to get the value "DoesNotWork" back, and then feed this into the
1-argument constructor.

more documentation on how defaults work is here: http://www.scala-lang.org/sid/1

lukas


On Tue, Mar 30, 2010 at 03:53, richard emberson <richard.emberson@gmail.com> wrote:
I'd like to create an instance using reflection. The
class has a single constructor which takes a parameter
which has a default value. How do I get to the correct
constructor in Scala?
Below is a test class which has one class with with two
constructors - and this one reflection works on. And
a second class which has a single constructor which
has a default value - and this one I can figure out how
to get a handle on so I can create an instance.

File Test.scala




import java.lang.reflect.Constructor

object Util {

 val EMPTY_CLASS_ARRAY = Array[Class[_]]()
 val EMPTY_OBJECT_ARRAY = Array[Any]()

}

class Builder[T](interfaceClass: Class[T]) {
 def lookupClass(name: String) : Class[_ <: T] = {
   var clz = Class.forName(name)
   clz.asSubclass(interfaceClass)
 }

 def getConstructor(clz: Class[_ <: T],
                    parameterTypes: Array[Class[_]]): Constructor[_ <: T] = {
   clz.getConstructor(parameterTypes: _*)
 }

 def newInstance(constructor: Constructor[_ <: T],
                 parameterValues: Array[Any]): T = {
   constructor.newInstance(parameterValues.map(_.asInstanceOf[AnyRef]) : _*)
 }
}

class Works(name: String) {
 def this() = this("Works")

 def getName: String = name
}

class DoesNotWork(name: String = "DoesNotWork") {
 def getName: String = name
}

import Util._

object Main {
 def doWorks {
   val builder = new Builder[Works](classOf[Works])
   var clz: Class[_ <: Works] = builder.lookupClass("Works")
   var constructor = builder.getConstructor(clz, EMPTY_CLASS_ARRAY)
   var works: Works = builder.newInstance(constructor, EMPTY_OBJECT_ARRAY)
   println("name="+works.getName)
 }
 def doesNotWork {
   val builder = new Builder[DoesNotWork](classOf[DoesNotWork])
   var clz: Class[_ <: DoesNotWork] = builder.lookupClass("DoesNotWork")
   var constructor = builder.getConstructor(clz, EMPTY_CLASS_ARRAY)
   var notworks: DoesNotWork = builder.newInstance(constructor, EMPTY_OBJECT_ARRAY)
   println("name="+notworks.getName)
 }
 def usage {
   println("Enter either: \"works\" or \"doesnotworks\"")
 }
 def main(args: Array[String]) {
   args match {
     case Array("works") => doWorks
     case Array("doesnotwork") => doesNotWork
     case _ => usage
   }

 }
}



> scalac Test.scala
> scala Main
Enter either: "works" or "doesnotwork"
> scala Main works
name=Works
> scala Main doesnotwork
java.lang.NoSuchMethodException: DoesNotWork.<init>()
       at java.lang.Class.getConstructor0(Class.java:2706)
       at java.lang.Class.getConstructor(Class.java:1657)
       at Builder.getConstructor(Works.scala:19)
       at Main$.doesNotWork(Works.scala:51)
       at Main$.main(Works.scala:61)
       at Main.main(Works.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 scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:55)
       at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:22)
       at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:61)
       at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:55)
       at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:61)
       at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:153)
       at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)


Using reflection how can I tell if a class has constructors that
have default parameters and how can I call the one that will
build an instance using the default value.

Thanks
Richard

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland