2009-10-29 20 views
7

Sto cercando di capire come istanziare un oggetto di classe case con la riflessione. C'è qualche supporto per questo? Il più vicino a cui sono arrivato sta guardando scala.reflect.Invocation, ma questo sembra più per l'esecuzione di metodi che fanno parte di un oggetto.istanziare l'oggetto con la riflessione utilizzando gli argomenti del costruttore

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

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

È vicino all'API che sto cercando.

Qualsiasi aiuto sarebbe apprezzato.

+0

Il riflesso qui coinvolto non ha nulla a che vedere con le classi di casi in particolare. Hai solo bisogno di un po 'di riflessione per digitare gli argomenti. Se sbaglio, puoi elaborare? – HRJ

+0

Sei corretto, eccetto che parte dell'obiettivo è essere in grado di scrivere semplici case classes e quindi usare un metodo come questo per istanziarle/modificarle. – justin

risposta

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 

Attualmente non c'è molto supporto per la riflessione in Scala. Ma puoi ricorrere all'API Java Reflection. Ma ci sono alcuni ostacoli:

  • È necessario creare un Array[AnyRef] e la scatola tuoi "tipi primitivi" nelle classi wrapper (java.lang.Integer, java.lang.Character, java.lang.Double, ...)

  • newInstance(Object ... args) Ottiene una matrice varargs di Object, così si dovrebbe dare il tipo inferer un suggerimento con :_*

  • newInstance(...) restituisce un Object quindi bisogna gettato indietro con asInstanceOf[T]

Il più vicino ho potuto ottenere per la vostra funzione instantiate è questo:

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 

Non è possibile ottenere la classe ottenere da un tipo generico. Java lo cancella (tipo cancellato).

Edit: September 20 2012

Tre anni dopo, il metodo instantiate può essere migliorato per restituire un oggetto correttamente digitato.

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

+0

come possiamo modificare il programma di cui sopra se abbiamo come valore di stringa di case class, cioè nel caso precedente diciamo che abbiamo input per il nostro programma come valore stringa di case class come "Foo" .So come costruire la classe di runtime basata sul valore di stringa della classe di caso – Aamir

+0

@Aamir Che dire di 'java.lang.Class.forName (" Foo ")'? –

2

Questo è quello che ho concluso finora, mi piacerebbe non dover trattare direttamente con AnyRef se possibile. Quindi se qualcuno conosce un modo per aggirare che apprezzerei l'aiuto.

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

Questo ti permette davvero di istanziare una classe che non conosci fino al runtime? Non esclude il parametro di tipo per la regola del metodo di istanza? –

+0

Capire questo pezzo era solo una piccola parte di quello che sto facendo.Sto solo sperimentando idee sull'utilizzo di oggetti immutabili in un livello di accesso ai dati. – justin

Problemi correlati