2010-04-17 19 views
10

Considere el siguiente código:Cómo acceder el valor de un campo a través de la reflexión (Scala 2.8)

class Foo(var name: String = "bar") 

ahora trato de obtener el valor y el tipo correcto de la misma a través de la reflexión:

val foo = new Foo 
val field = foo.getClass.getDeclaredField("name") 
field.setAccessible(true) 
//This is where it doesn't work 
val value = field.get(????) 

Intenté cosas como field.get (foo), pero eso solo devuelve un java.lang.Object pero no String. Básicamente, necesito el tipo correcto, porque quiero invocar un método en él (por ejemplo, toCharArray).

¿Cuál es la forma sugerida de hacerlo?

Respuesta

0

Parece que no es posible hacer lo que quiera con a tratar todos los posibles tipos a mano e. gramo.

o match { 
    case I if o.isInstanceOf[Int] => val i = I.asInstanceOf[Int] 
    case F if o.isInstanceOf[Float] => val f = I.asInstanceOf[Float] 
    case S if o.isInstanceOf[String] => val s = I.asInstanceOf[String] 
    case OF if o.getGenericType.toString == "scala.Option<java.lang.Float>" => val of = OF.asInstanceOf[Option[Float]] 
    . 
    . 
    . 

Bueno, esperemos que habrá un idioma en el futuro en el que algo como esto funciona ...

3

getDeclaredField es un método de java.lang.Class.

Tienes que cambiar foo.getDeclaredField("name") por foo.getClass.getDeclaredField("name") (o classOf[Foo].getDeclaredField("name")) para obtener el campo.

Puede obtener el tipo con el método getType en la clase Field pero no lo ayudará porque devuelve Class[_]. Dado que usted sabe que el tipo es una Cadena, siempre puede emitir el valor devuelto usando field.get(foo).asInstanceOf[String]

+0

Arreglé el getClass que faltaba, esto era solo un descuido. Me pregunto cómo hacer el reparto sin saber qué es de antemano. Si supiera todo sobre la clase que tengo que manejar, no necesitaría reflexión ... ¡Gracias por las sugerencias! – soc

+0

Puede emparejar el objeto con algo similar a 'valor match {case s: String =>/* hacer algo con una cadena */case _ =>/* hacer otra cosa * /}'. No sé si entiendo lo que quieres hacer. – gerferra

1

AFAIK, la reflexión siempre funciona con Objeto, y usted tiene que emitir los resultados usted mismo.

+0

Sí, he entendido mal la pregunta, ahora he cambiado mi respuesta. – gerferra

5

Como han mencionado otros, los métodos de reflexión devuelven Object por lo que tiene que emitir. Puede que sea mejor utilizar el método que el compilador Scala crea para el acceso de campo en lugar de tener que cambiar la visibilidad del campo privado. (No estoy seguro si el campo privado nombre se garantiza que sea la misma que la de los métodos de acceso.)

val foo = new Foo 
val method = foo.getClass.getDeclaredMethod("name") 
val value = method.get(foo).asInstanceOf[String] 
+0

funciona bien con ** foo.getClass.getDeclaredField ("nombre") ** porque foo.getClass.getDeclaredMethod no tiene un miembro llamado * get * – Kruser

0

Esto es cómo se puede obtener la lista de nombres de campos y su valor de una clase de caso:
Primero, usando la reflexión, obtenga la información de los campos de la siguiente manera:

val TUPLE2_OF_FIELDNAME_TO_GETTERS = typeOf[<CLASS>].members 
.filter(!_.isMethod) 
.map(x => (x.name.toString, classOf[<CLASS>].getDeclaredMethod(x.name.toString.trim))) 

¿Cómo usarlo?

getFieldNameAndValue(obj: <CLASS>): Seq[(String, String)] { 
    var output = Seq[(String, String)]() 
for(fieldToGetter <- TUPLE2_OF_FIELDNAME_TO_GETTERS) { 
     val fieldNameAsString = fieldToGetter._1 
     val getter = fieldToGetter._2 
     val fieldValue = getter.invoke(obj).toString 
     output += (fieldName, fieldValue) 
    } 
} 
Cuestiones relacionadas