Jede Art und Weise den Typ einer Scala Option Erklärung zur Laufzeit für den Zugriff auf die Reflexion?
-
27-09-2019 - |
Frage
Also, ich habe eine Scala-Klasse, die wie folgt aussieht:
class TestClass {
var value: Option[Int] = None
}
, und ich bin der Bekämpfung ein Problem, wo ich einen String-Wert haben, und ich will es in dieser Option zwingen [Int] zur Laufzeit mit Reflexion. Also, in einem anderen Teil des Codes (das weiß nichts von Testclass) Ich habe einige Code wie folgt aus:
def setField[A <: Object](target: A, fieldName: String, value: String) {
val field = target.getClass.getDeclaredField(fieldName)
val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ?
field.set(target, coercedValue)
}
Um dies tun, ich muss wissen, dass das Feld eine Option ist und dass der Typ-Parameter der Option ist Int.
Was sind meine Optionen für herauszufinden, dass die Art der ‚Wert‘ ist eine Option [Int] zur Laufzeit (Reflexion h verwendet wird)?
Ich habe ähnliche Probleme mit Anmerkungen versehen, das Feld gelöst gesehen, z.B. @OptionType (Int.class). Ich würde eine Lösung bevorzugen, die nicht Anmerkungen auf dem Reflexionsziel möglichst erforderlich waren.
Lösung
Es ist ziemlich streightforward mit Java 1.5 Reflection-API:
def isIntOption(clasz: Class[_], propertyName: String) = {
var result =
for {
method <- cls.getMethods
if method.getName==propertyName+"_$eq"
param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
} yield
param.getActualTypeArguments.toList == List(classOf[Integer])
&& param.getRawType == classOf[Option[_]]
if (result.length != 1)
throw new Exception();
else
result(0)
}
Andere Tipps
Auf der Byte-Code-Ebene, Java hat Generics nicht bekommt. Generics mit Polymorphismus implementiert, so dass, sobald Sie Ihren Quellcode (in diesem Fall Scala) kompiliert wird, generische Typen verschwinden (das nennt man Typ Löschung ). Dies macht nicht möglich Allgemeinlaufzeittypinformationen über Reflexion zu sammeln.
Eine mögliche --though wenig dirty-- Abhilfe ist, den Laufzeittyp einer Eigenschaft zu erhalten, Sie wissen, dass es den gleichen Typ wie der generische Parameter hat. Für Option Instanzen können wir get
Mitglied
object Test {
def main(args : Array[String]) : Unit = {
var option: Option[_]= None
println(getType(option).getName)
option = Some(1)
println(getType(option).getName)
}
def getType[_](option:Option[_]):Class[_]= {
if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
}
}
class TestClass {
var value: Option[Int] = None
// ...
def doSomething {
value match {
case Some(i) => // i is an Int here
case None =>
// No other possibilities
}
}
}
Das Problem ist, dass JVM implementiert Generika durch Typ Löschung. So ist es unmöglich, durch Reflexion zu entdecken, dass die Art der value
Option[Int]
liegt daran, dass bei der Laufzeit tatsächlich ist es nicht: es ist nur Option
2,8 Sie sollten Verwendung der Lage sein, Manifests
wie folgt aus:
var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))