tutorial traduccion peliculas descargar app groovy

groovy - traduccion - Una forma maravillosa de invocar dinámicamente un método estático



groovy traduccion (6)

Sé que en Groovy puedes invocar un método en una clase / objeto usando una cadena. Por ejemplo:

Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1)

¿Hay alguna manera de hacer esto con la clase? Tengo el nombre de la clase como una cadena y me gustaría poder invocar dinámicamente esa clase. Por ejemplo, buscando hacer algo como:

String clazz = "Foo" "$clazz".get(1)

Creo que me estoy perdiendo algo realmente obvio, simplemente no soy capaz de resolverlo.


Aquí hay otra manera

import org.codehaus.groovy.grails.commons.ApplicationHolder as AH def target = application.domainClasses.find{it.name == ''ClassName''} target.clazz.invokeMethod("Method",args)

Con esto, no necesita especificar el nombre del paquete. Sin embargo, ten cuidado si tienes el mismo nombre de clase en dos paquetes diferentes.


Como lo sugirió Guillaume Laforge en Groovy ML,

("Foo" as Class).get(i)

daría el mismo resultado.

He probado con este código:

def name = "java.lang.Integer" def s = ("$name" as Class).parseInt("10") println s


Estoy ejecutando la versión 1.8.8 groovy ... y el simple ejemplo funciona.

Import my.Foo def myFx="myMethodToCall" def myArg = 12 Foo."$myFx"(myArg)

Llama a Foo.myMethodToCall (12) como se esperaba y se desea. No sé si esto siempre ha sido así.


Melix en Groovy ML me apuntó en la dirección "derecha" sobre la invocación dinámica del método de clase por un tiempo atrás, bastante útil:

// define in script (not object) scope def loader = this.getClass().getClassLoader() // place this in some MetaUtils class, invoked on app startup String.metaClass.toClass = { def classPath = getPath(delegate) // your method logic to determine ''path.to.class'' Class.forName(classPath, true, this.loader) } // then, anywhere in your app "Foo".toClass().bar()

También puede crear otro método de cadena metaClass para crear instancias, refactorizando según corresponda:

String.metaClass.toObject = { def classPath = getPath(delegate) Class.forName(classPath, true, this.loader).newInstance() }

Groovy es pura diversión; -)


Prueba esto:

def cl = Class.forName("org.package.Foo") cl.get(1)

Un poco más pero debería funcionar.

Si desea crear un código tipo "interruptor" para métodos estáticos, sugiero crear una instancia de las clases (incluso si tienen solo métodos estáticos) y guardar las instancias en un mapa. Puedes usar

map[name].get(1)

para seleccionar uno de ellos.

[EDIT] "$name" es un GString y como tal una declaración válida. "$name".foo() significa "llamar al método foo() de la clase GString .

[EDIT2] Cuando se utiliza un contenedor web (como Grails), debe especificar el cargador de clases. Hay dos opciones:

Class.forName("com.acme.MyClass", true, Thread.currentThread().contextClassLoader)

o

Class.forName("com.acme.MyClass", true, getClass().classLoader)

La primera opción funcionará solo en un contexto web, el segundo enfoque también funciona para pruebas unitarias. Depende del hecho de que generalmente pueda usar el mismo cargador de clases que la clase que invoca forName() .

Si tiene problemas, use la primera opción y configure el contextClassLoader en su prueba de unidad:

def orig = Thread.currentThread().contextClassLoader try { Thread.currentThread().contextClassLoader = getClass().classLoader ... test ... } finally { Thread.currentThread().contextClassLoader = orig }


Un aumento a la respuesta de Chanwit que ilustra la creación de una instancia:

def dateClass = ''java.util.Date'' as Class def date = dateClass.newInstance() println date