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