Un modo per accedere al tipo di una dichiarazione opzione Scala in fase di esecuzione utilizzando la riflessione?

StackOverflow https://stackoverflow.com/questions/2664114

Domanda

Quindi, ho una classe Scala che assomiglia a questo:

class TestClass {
  var value: Option[Int] = None
}

e sto affrontando un problema in cui ho un valore String e voglio costringere in che l'opzione [Int] in fase di esecuzione utilizzando la riflessione. Così, in un altro pezzo di codice (che non sa nulla di TestClass) ho qualche codice come questo:

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)   
}

Per fare questo, ho bisogno di sapere che il campo è una possibilità e che il parametro tipo di opzione è Int.

Quali sono le opzioni per capire che il tipo di 'valore' è Opzione [Int] in fase di esecuzione (vale a dire utilizzando la riflessione)?

ho visto problemi simili risolti annotando il campo, ad esempio @OptionType (Int.class). Preferirei una soluzione che non richiedesse annotazioni sul target di riflessione, se possibile.

È stato utile?

Soluzione

E 'abbastanza streightforward utilizzando Java 1.5 riflessione 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)
 }

Altri suggerimenti

A livello di bytecode, Java non ha ottenuto Generics. Generics sono implementati con il polimorfismo, quindi una volta che il codice sorgente (in questo caso Scala) viene compilato, i tipi generici scompaiono (questo è chiamato digitare la cancellazione ). Questo non ha possibilità di raccogliere informazioni di tipo generico di runtime attraverso la riflessione.

Una possibile soluzione poco dirty-- --though è quello di ottenere il tipo di esecuzione di una proprietà sapere non ha lo stesso tipo come parametro generico. Per le istanze di opzione possiamo utilizzare membro get

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
    }
  }
}

Il problema è che implementa JVM generici attraverso la cancellazione di tipo. Quindi è impossibile scoprire attraverso la riflessione che il tipo di value è Option[Int] perché al run-time che in realtà non è: è solo Option

In 2,8 si dovrebbe essere in grado di utilizzare Manifests in questo modo:

var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top