2009-10-29 9 views
7

Estoy tratando de encontrar la forma de crear una instancia de un objeto de clase de caso con reflexión. ¿Hay algún apoyo para esto? Lo más cercano que he venido es mirando scala.reflect.Invocation, pero esto parece más para ejecutar métodos que son parte de un objeto.instancia de objeto con reflexión utilizando argumentos de constructor

case class MyClass(id:Long, name:String) 

def instantiate[T](className:String)(args:Any*) : T = { //your code here } 

Está cerca de la API que estoy buscando.

Cualquier ayuda sería apreciada.

+0

La reflexión involucrado aquí no tiene nada que ver con las clases de caso en concreto. Solo necesitas un poco de reflexión para encasillar los args. Si estoy equivocado, ¿pueden dar más detalles? – HRJ

+0

Tiene razón, excepto que parte del objetivo es poder escribir clases de casos simples y luego usar un método como este para instanciarlos/modificarlos. – justin

Respuesta

18
scala> case class Foo(id:Long, name:String) 
defined class Foo 

scala> val constructor = classOf[Foo].getConstructors()(0) 
constructor: java.lang.reflect.Constructor[_] = public Foo(long,java.lang.String) 

scala> val args = Array[AnyRef](new java.lang.Integer(1), "Foobar") 
args: Array[AnyRef] = Array(1, Foobar) 

scala> val instance = constructor.newInstance(args:_*).asInstanceOf[Foo] 
instance: Foo = Foo(1,Foobar) 

scala> instance.id 
res12: Long = 1 

scala> instance.name 
res13: String = Foobar 

scala> instance.getClass 
res14: java.lang.Class[_] = class Foo 

Actualmente no hay mucho soporte de reflexión en Scala. Pero puede recurrir a la API de reflexión de Java. Sin embargo, hay algunos obstáculos:

  • Tienes que crear un Array[AnyRef] y la caja sus "tipos primitivos" en las clases de envoltura (java.lang.Integer, java.lang.Character, java.lang.Double, ...)

  • newInstance(Object ... args) Obtiene una matriz varargs de Object, por lo que debe dar el tipo inferer una pista con :_*

  • newInstance(...) devuelve un Object por lo que tienen que desechar de nuevo con asInstanceOf[T]

Lo más cerca que podía llegar a su función instantiate es la siguiente:

def instantiate(clazz: java.lang.Class[_])(args:AnyRef*): AnyRef = { 
    val constructor = clazz.getConstructors()(0) 
    return constructor.newInstance(args:_*).asInstanceOf[AnyRef] 
} 

val instance = instantiate(classOf[MyClass])(new java.lang.Integer(42), "foo") 
println(instance)   // prints: MyClass(42,foo) 
println(instance.getClass) // prints: class MyClass 

no se puede conseguir la clase recibe de un tipo genérico. Java lo borra (escribe borrado).

Editar: 20 Septiembre 2012

Tres años después, el método instantiate se puede mejorar para devolver un objeto correctamente escrito.

Ver http://www.nabble.com/How-do-I-get-the-class-of-a-Generic--td20873455.html

+0

¿cómo podemos modificar el programa anterior si tenemos entrada como valor de cadena de la clase de caso, es decir, en el caso anterior digamos que tenemos entrada a nuestro programa como valor de cadena de la clase de caso como "Foo". Así cómo construir clase de tiempo de ejecución basado en el valor de cadena de la clase de caso – Aamir

+0

@Aamir ¿Qué pasa con 'java.lang.Class.forName (" Foo ")'? –

2

Esto es lo que he terminado hasta ahora, me gustaría no tener que tratar directamente con AnyRef si es posible. Entonces, si alguien conoce una forma de moverse, agradecería la ayuda.

case class MyClass(id:Long,name:String) 

def instantiate[T](classArgs: List[AnyRef])(implicit m : Manifest[T]) : T ={ 
     val constructor = m.erasure.getConstructors()(0) 
     constructor.newInstance(classArgs:_*).asInstanceOf[T] 
    } 

val list = List[AnyRef](new java.lang.Long(1),"a name") 
val result = instantiate[MyClass](list) 
println(result.id) 
+0

¿Esto realmente le permite instanciar una clase que no conoce hasta el tiempo de ejecución? ¿El parámetro de tipo al método de creación de instancias no lo descarta? –

+0

Calcular esta pieza fue solo una pequeña parte de lo que estoy haciendo.Solo estoy experimentando con ideas de usar objetos inmutables en una capa de acceso a datos. – justin

Cuestiones relacionadas