2008-12-13 15 views
10

Actualmente estoy trabajando con un lenguaje de programación especializado e interpretado implementado en Java. Como una parte muy pequeña del lenguaje, me gustaría agregar la capacidad de hacer llamadas a Java. Antes de sumergirme en todo lo esencial de la reflexión, me preguntaba si alguien sabía de una biblioteca general para hacer la parte de "back-end" de invocar el código de Java de forma reflexiva.¿Existe una biblioteca general "back-end" para la reflexión de Java

Es decir, analizo una cadena (defino la gramática) en una estructura de datos que representa una llamada al método Java (o constructor o acceso de campo) y luego transfiero esa estructura de datos a esta biblioteca que invoca la llamada y regresa el resultado. En particular, me gustaría que le permite manejar ya todos los casos extremos que no quiero averiguar:

  • Automáticamente escoger el método correcto basado en los tipos de argumentos (como un Class.getDeclaredMethod inteligente ())
  • distinción entre las matrices y la manija normal de objeto hace referencia a
  • etc

me he pasado un poco de tiempo mirando las implementaciones de lenguajes dinámicos en la JVM, pero estos son generalmente mucho más complicado de lo Estoy buscando, o altamente optimizado para el partic lenguaje ular

Otra opción es convertir mi gramática en una cadena en un lenguaje dinámico e invocarlo con Rhino o algo así, pero eso es un poco más por encima de lo que estoy buscando.

Gracias!

Respuesta

6

Solo un comentario para su propia respuesta; en realidad beanutils tiene soporte para obtener "una coincidencia cercana" dado un conjunto de parámetros. Ver getMatchingAccessibleMethod()

BeanUtils es realmente potente y tiene muchos métodos de utilidad para inspeccionar clases. El mismo soporte está naturalmente disponible para los constructores.

2

Eche un vistazo a Java's scripting support; Creo que te ayudará a abordar tu problema.

+0

Nope. Estoy buscando algo con un método como "invocación de objeto (objeto Object, String nameOfMethod, Object [] args)" que encuentra el método correcto (teniendo en cuenta la herencia y la conversión de tipo) y lo llama. Las secuencias de comandos de Java simplemente nos permiten evaluar cadenas en un lenguaje de scripts existente. –

+0

Bueno, Java scripting hace algo más que permitirle invocar lenguajes de scripting desde Java, si no me equivoco, proporciona mecanismos para permitir que el código de scripting interactúe con objetos Java (referido como Binding en los documentos), que se ve muy similar a lo que estamos tratando de hacer – alex

+0

... al menos, echar un vistazo a las implementaciones de scripts existentes debería ayudarlo – alex

7

Pruebe el módulo FEST Reflection. Es una forma fluida de hacer la reflexión de Java. Por ejemplo:

String name = method("get").withReturnType(String.class) 
         .withParameterTypes(int.class) 
         .in(names) 
         .invoke(8); 
0

Terminé yendo con la sugerencia de Alex. BeanUtils ayuda mucho a los frijoles, pero no quiero trabajar únicamente con frijoles. FEST se ve muy bien y lo he marcado para seguir estudiándolo, pero al igual que BeanUtils, no parece resolver lo que considero que es el problema difícil aquí. A saber, dado el nombre de un método y la lista de argumentos, elija el método que mejor se ajuste a los argumentos. Si un método toma un flotante y tengo un doble, debe ser lo suficientemente inteligente como para no rechazar ese método porque la firma no coincide exactamente.

Obviamente, los lenguajes de scripts creados en la JVM resuelven este problema, pero de una manera mucho más complicada de lo que necesito debido a las optimizaciones específicas del idioma. Por lo tanto, como se trata de una característica menor y experimental, he elegido una solución expedita utilizando el soporte del motor de scripting (JavaScript, en particular) en Java 1.6. Aquí está la idea básica:

private ScriptEngine engine = ... initialize with JavaScript engine ... 

private Object invoke(Object object, String methodName, Object[] args) 
    throws RhsFunctionException 
{ 
    // build up "o.method(arg0, arg1, arg2, ...)" 
    StringBuilder exp = new StringBuilder("o." + methodName); 
    engine.put("o", object); 
    buildArgs(arguments, exp); 

    try { 
     return engine.eval(exp.toString()); 
    } 
    catch (ScriptException e) { 
     throw new RhsFunctionException(e.getMessage(), e); 
    } 
} 

private void buildArgs(Object[] args, StringBuilder exp) 
{ 
    // Use bindings to avoid having to escape arguments 
    exp.append('('); 
    int i = 0; 
    for(Symbol arg : args) { 
     String argName = "arg" + i; 
     engine.put(argName, arg); 
     if(i != 0) { 
      exp.append(','); 
     } 
     exp.append(argName); 
     ++i; 
    } 
    exp.append(')'); 
} 

Obviamente, hay un poco más, pero esta es la idea básica. Realmente no me gusta construir una cuerda y evaluarla, pero al usar las ataduras sugeridas por Alex, evito la mayoría de las trampas que escapan. Además, tengo una interfaz limpia y simple que puedo intercambiar con una implementación "real" si resulta necesario.

Cualquier comentario o solución alternativa son más que bienvenidos.

1

Consideraría también echar un vistazo a los resortes de la clase ReflectionUtils. Manejo de reflexión muy potente.

1

plantear esta entre los muertos:

invoke(Object object, String methodName, Object[] args) 

Apache Commons Lang tiene exactamente ese método. MethodUtils#invoke

1

que han comenzado a crear una biblioteca com.lexicalscope.fluent-reflexión: fluido-reflexión que se integra con hamcrest y lambdaj

Puede escribir código como este; el cual llama a todos los métodos de post construcción anotados en una clase:

forEach(
    object(subject).methods(annotatedWith(PostConstruct.class)), 
    ReflectedMethod.class).call(); 

Blog post aquí: http://www.lexicalscope.com/blog/category/software-projects/fluent-reflection/

Documentación aquí: http://fluent-reflection.lexicalscope.com/

Se puede llegar desde aquí el centro de experta: http://repo1.maven.org/maven2/com/lexicalscope/fluent-reflection/fluent-reflection/

Tiene algunas características básicas que faltan en este momento, como el acceso a los campos, pero funciona para los métodos. Probablemente demore un tiempo llegar a un punto estable en realidad (como uno o dos años), ya que solo estoy trabajando ocasionalmente. Pero está desarrollado con un estándar de calidad bastante alto (espero) y es de código abierto, así que básicamente puedes usarlo tal como está ahora si tiene todas las características que necesitas (es posible que tengas que ajustar tu código un poco si quieres para usar las versiones más nuevas que se lanzan). Lo estoy usando en algún código de producción en ese momento.

Está diseñado para ser bastante extensible, por lo que puede agregar estrategias para encontrar los métodos que desea en un estilo ligeramente acoplado (de composición). Por lo tanto, si no tiene la estrategia exacta de búsqueda de métodos que desea, es de esperar que sea fácil de agregar.

+0

Eso se ve muy poderoso. ¿Tienes también 1 o 2 ejemplos más simples? –

+0

Y un ejemplo de selección de todos los métodos get: objeto (sujeto) .methods (callableHasNameStartingWith ("get"). Y (callableHasNoArguments()). And (not (callableHasVoidReturn()))); – lexicalscope

2

Si está buscando la simplicidad, he creado una biblioteca simple llamada jOOR para facilitar el acceso a la API de reflexión en Java. Es compatible con las acciones más esenciales sin construir una gran API. Aquí hay un ejemplo de cómo se ve el código jOOR:

String world = 
on("java.lang.String") // Like Class.forName() 
.create("Hello World") // Call the most specific matching constructor 
.call("substring", 6) // Call the most specific matching substring() method 
.call("toString")  // Call toString() 
.get()     // Get the wrapped object, in this case a String 
Cuestiones relacionadas