2011-10-13 1 views
22

Le risposte di this question about the Groovy way to dynamically invoke a static method sono stati molto utili, ma sto avendo problemi con il seguente caso:modo Groovy per istanziare dinamicamente una classe da String

ho definito una semplice classe Groovy:

class Item { 
    def id = 1 
    def data = [ "a", "b" ] 
} 

Ho poi definita una semplice classe di utilità che vuole caricare dinamicamente la classe dell'oggetto:

class Util { 
    static def main(args) { 
    def cls = "Item" as Class 
    def instance = cls.newInstance() 
    println instance.toString() 
    } 
} 

Util.groovy si trova nella stessa cartella come Item.groovy

Quando provo a fare funzionare Util.groovy ricevo il seguente errore:

Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: 
Cannot cast object 'Item' with class 'java.lang.String' 
to class 'java.lang.Class' due to: 
java.lang.ClassNotFoundException: Item 
     at Util.main(Util.groovy:3) 

L'unico modo che ho potuto fare il lavoro era utilizzando groovyc di precompilare Item.groovy, ma questo non coglie il punto di essere Groovy :)

risposta

28

questo funziona, utilizzando il underlying GroovyClassLoader:

def instance = this.class.classLoader.loadClass('Item', true, false)?.newInstance() 
+1

Probabilmente dovresti cambiare 'this.class' in' this.getClass() '. In generale, si consiglia di utilizzare il metodo completo per evitare [ricerche di proprietà o di mappe (o invocare le sovrascritture del metodo)] (http://groovy.329449.n5.nabble.com/class-vs-getClass-td368617.html). – OverZealous

+8

Perché preoccuparsi quando sappiamo che questa non è una mappa? Abbraccia la dinamica! ;-) –

+0

Ha funzionato! Grazie Tim! :) –

5

ho dovuto fare questo e ha trovato un modo interessante - così ho pensato di tornare e parlarne.

ho avuto un problema con questo perché volevo passare un valore per newInstance (utilizzare un costruttore non predefinito) e tutte le soluzioni sembrava di essere un po 'di lavoro (sono pigro, va bene?)

In ogni caso, supponiamo che si desidera creare un nuovo Integer (5) ... provate questo:

c = "java.lang.Integer" 
p = "5" 
def result = Eval.me("return new ${c}(${p})") 
assert(result == 5) 

lavorato veramente bene anche se sono sicuro si tratta di una soluzione più lento possibile. Ha il vantaggio che il metodo è applicabile a molte altre situazioni.

+3

IT SEEMS javascript plagia :) –

+0

@Bill Interessante a livello intellettuale, ma questo non è davvero eccezionale, come Abdennour TOUMI ha detto –

+0

Sono d'accordo, appena accennato per completezza e facilità - a volte stai solo scrivendo un off script e questo è facile da ricordare e flessibile. –