Cualquier forma de acceder al tipo de una declaración Opción Scala en tiempo de ejecución utilizando la reflexión?

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

Pregunta

Por lo tanto, tengo una clase Scala que es similar al siguiente:

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

y estoy frente a un problema en el que tengo un valor de cadena y quiero coaccionar en que la opción [Int] en tiempo de ejecución utilizando la reflexión. Por lo tanto, en otra pieza de código (que no sabe nada sobre TestClass) Tengo algo de código como el siguiente:

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

Para hacer esto, necesito saber que el campo es una opción y que el parámetro de tipo de la opción se Int.

¿Cuáles son mis opciones para averiguar que el tipo de 'valor' es la opción [Int] en tiempo de ejecución (es decir, utilizando la reflexión)?

I han visto problemas similares que resuelve anotar el campo, por ejemplo, @OptionType (Int.class). Yo preferiría una solución que no requiere anotaciones en el objetivo de la reflexión, si es posible.

¿Fue útil?

Solución

Es bastante streightforward utilizando Java API 1.5 reflexión:

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

Otros consejos

A nivel de código de bytes, Java no ha conseguido los genéricos. Los medicamentos genéricos se implementan con el polimorfismo, por lo que una vez que se compila el código fuente (en este caso Scala), desaparecen los tipos genéricos (esto se llama escriba borrado ). Esto hace que no sea posible reunir información de tipo genérico en tiempo de ejecución a través de la reflexión.

Una posible solución poco dirty-- --aunque es obtener el tipo de tiempo de ejecución de una propiedad usted sabe que tiene el mismo tipo que el parámetro genérico. Para los casos de opción podemos utilizar miembro 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
    }
  }
}

El problema es que implementa JVM genéricos a través de tipo de borrado. Por lo que es imposible descubrir a través de la reflexión de que el tipo de value es Option[Int] porque en el tiempo de ejecución en realidad no lo es: es sólo Option

2.8 que debería ser capaz de utilizar Manifests como esto:

var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top