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.

War es hilfreich?

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

verwenden
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))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top