2010-07-22 10 views
8

Tengo una funcionalidad que deseo ofrecer a un cliente por una maqueta de software que estamos preparando - y quiero saber si esencontrar nuevas clases de Java en tiempo de ejecución

  1. posible
  2. inteligente (también conocido como no estúpida)
  3. lo mejor

Quiero que el cliente sea capaz de escribir una clase java que implementa la interfaz de mi Computable y pegarlo en alguna carpeta predeterminada. Esta carpeta contendrá los archivos .java en lugar de los archivos .class. Luego, en tiempo de ejecución, quiero que mi programa busque esa carpeta y extraiga todo el Computables de esa carpeta y los almacene en un mapa desde el nombre del Computable al objeto Computable. El Computable solo debe tener un constructor predeterminado y la interfaz solo tendrá un método llamado compute que asigna una matriz de Object a Object.

+0

¿Desea compilar los archivos de los usuarios en tiempo de ejecución? – jedierikb

+0

¿Tiene que ser el idioma en sí, o sería correcto otro lenguaje de scripting? – skaffman

+0

@jedierikb Si es bastante fácil de compilar en tiempo de ejecución, estaría bien. Simplemente no quiero que el cliente tenga que preocuparse por arrastrar archivos de clase. – JnBrymn

Respuesta

9

El Java Compiler API introducido en Java SE 6 debería darle lo que necesita.

+0

Tenga en cuenta que esta API solo está disponible en JDK, no en JRE. Entonces, si alguna vez tiene la intención de distribuirlo, el usuario/usuario final debe tener instalado JDK y esto es bastante poco común entre el público principal. – BalusC

+0

¡Ay! Gracias @BalusC. – djna

+0

@BalusC ¿La 'x' al final de javax siempre implica esto? – JnBrymn

0
+0

Parecía prometedor, pero parece girar en torno a dos posibles soluciones. 1) Use una API que un tipo haya creado para sí mismo (no quiero arriesgarme a jugar con el framework de otra persona en el poco tiempo que me queda) o 2) Usar la reflexión para descubrir qué clases ya cargadas implementan 'Computable'. Recuerda que mis clases no se cargarán ... solo son archivos .java. – JnBrymn

0

I que esto sería más simple si se le permite a su cliente a escribir en una declaración de código usando algo como maravilloso, que es lo suficientemente Java-ish, y fácil de ejecutar en tiempo de ejecución de un valor de cadena.

+0

¿No es Groovy un superconjunto estricto? Si es así, supongo que podría decirle a su cliente que está tomando Java y que no serán más sabios. –

+0

Ah, estoy equivocado. Un archivo java es casi siempre un código groovy válido, pero no es un superconjunto estricto. –

1

Si es fácil de compilar en tiempo de ejecución, estaría bien.

Puede usar javax.tools para realizar la compilación según sea necesario. Create dynamic applications with javax.tools puede ayudar, también. También es posible hacerlo in memory.

Una advertencia: el uso del compilador crea una dependencia en el JDK; el JRE solo es insuficiente.

+0

¿Tiene algún código de muestra? ¿Dirijo la línea de comando desde Java para ejecutar javac? ¿Cómo creo que chupar el archivo de la clase y construir la clase? – JnBrymn

+0

@John Berryman: Agregué un enlace arriba. – trashgod

0

Es bastante fácil para recorrer la lista de archivos en una carpeta. Alguien mencionó que es posible llamar al compilador de Java desde Java (¡si redistribuye el JDK, que creo que es un punto cuya legalidad necesita ser revisada!) Esa es una gran parte de la batalla.

Parece que tiene en mente un modelo fijo donde solo se extraen archivos de una determinada interfaz de la carpeta. Creo que aquí es donde tu método debe dar un poco. La manera sensata (IMO) de hacerlo sería compilar todos los archivos en esa carpeta, y luego con sus clases guardadas en alguna parte, puede cargarlas y reflejarlas y luego determinar cuáles de ellas "hacen" la interfaz y cuáles no 't. Aquellos que no lo hagan se cargarán innecesariamente en su JVM, pero a menos que sea intencionalmente muy desperdiciador de espacio, el código que no ejecuta no puede dañar su programa.

Después de haber determinado cuáles son las cosas computables, puede almacenar esas clases (o instancias de las mismas) en una Colección y hacer lo que quiera con ellas. Simplemente ignora los otros.

3

Puede encontrar que Google Reflections es útil para encontrar clases implementando/ampliando una cierta interfaz/superclase en el classpath. Es entonces tan sencillo como

Reflections reflections = new Reflections("my.project.prefix"); 
Set<Class<? extends SomeClassOrInterface>> subTypes = reflections.getSubTypesOf(SomeClassOrInterface.class); 

Entonces, para probar si en verdad tiene un constructor predeterminado sin argumentos, simplemente comprobar si para cada Class#newInstance() no lanza ninguna excepción.

+0

Entonces, ¿qué ocurre si el archivo .class no está en la ruta actual, sino en una carpeta que solo conocemos en tiempo de ejecución? – JnBrymn

+1

Puede agregar rutas a la ruta de clases durante el tiempo de ejecución utilizando ['URLClassLoader'] (http://java.sun.com/javase/6/docs/api/java/net/URLClassLoader.html). – BalusC

0

Puede usar BeanShell. Esta biblioteca es pequeña y no requiere el JDK. Se usa en varios IDE y servidores web. La última versión parece tener el soporte que necesita para cargar archivos .java desde la ruta de clase. (Todavía en versión beta)

Cuestiones relacionadas