mercredi 23 octobre 2019

Determining constructor parameter count and type via reflection in Scala

I have about a hundred small classes that inherit a trait. The classes are instantiated in a factory via reflection based on their names.

Class.forName(name).getConstructor().newInstance().asInstanceOf[Trait])

Now requirements have changed such that one and only one of the classes needs to take a parameter during construction. I am trying to change the factory to handle this new case. The REPL worksheet with my approach looks like this:

import java.lang.reflect.Constructor

trait T {
  def p: Unit
}

class C1 extends T {
  override def p = println("no ymd")
}

class C2(a: Array[String]) extends T {
  override def p = println(s"year: ${a(0)}")
}

class C3(a: Array[Int]) extends T {
  override def p = println(s"day: ${a(2)}")
}

val ymd = Array("2019","10","23")
val ymd_int = Array(2019,10,23)

def getT(c: Class[_]): T = {
  c.getConstructors match {
    case Array(c: Constructor[Array[String]]) => c.newInstance(ymd).asInstanceOf[T]
    case Array(c: Constructor[Array[Int]]) => c.newInstance(ymd_int).asInstanceOf[T]
    case Array(c: Constructor[_]) => c.newInstance().asInstanceOf[T]
    case _ => throw new Exception("...")
  }
}

getT(classOf[C1]).p
getT(classOf[C2]).p
getT(classOf[C3]).p 

In the REPL, I'm using classOf instead of Class.forName because class names in the REPL are kind of wonky.

During complication I'm getting the warnings:

Warning:(25, 23) non-variable type argument Array[String] in type
pattern java.lang.reflect.Constructor[Array[String]] is unchecked 
since it is eliminated by erasure 
case Array(c: Constructor[Array[String]]) =>
    c.newInstance(ymd).asInstanceOf[T]

and

Warning:(26, 23) non-variable type argument Array[Int] in type
pattern java.lang.reflect.Constructor[Array[Int]] is unchecked 
since it is eliminated by erasure
case Array(c: Constructor[Array[Int]]) =>
    c.newInstance(ymd_int).asInstanceOf[T]

And then of course the calls to getT are failing because the three case statements look identical at run time and so all three calls are being handled by the first case.

Please Help.





Aucun commentaire:

Enregistrer un commentaire