Compile archivos Java mediante programación

Sé que esto se ha preguntado y respondido mucho, pero todavía no tengo una buena solución y todavía no entiendo algunas partes. Así que tengo el requisito de compilar archivos * .java mediante programación.

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

es lo que estoy usando y (como se esperaba) es el compilador null. Ahora, sé que tengo que usar el JDK y no el JRE como un "tiempo de ejecución", pero aquí hay algo que no entiendo: ¿no es suficiente con poner tools.jarel classpath de la aplicación y luego tener acceso? a la API del compilador de Java? Si esto es cierto, ¿hay (creo que hay) diferencia entre una aplicación Java independiente y una aplicación basada en web. En realidad, estoy tratando de invocar el JavaCompiler desde una aplicación web PlayFramework, así que descubrí, ¿tal vez estas soluciones (con la inclusión de tools.jar) solo funcionan para aplicaciones independientes?

También intenté crear un ClassLoader personalizado e invocar el método mencionado anteriormente con reflexión, pero todo lo que obtengo es nullpara el compilerobjeto:

ClassLoader classloader = app.classloader();
File file = new File("lib/tools.jar");          
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
ClassLoader newCL = new URLClassLoader(urls, classloader) {
};
Class<?> loadClass = newCL.loadClass("javax.tools.ToolProvider");
Method method = loadClass.getMethod("getSystemJavaCompiler", null);             
Object object = method.invoke(null);
System.out.println("Object: " + object); // NULL

Explicación del código anterior:

  • No he incluido try / catches por simplicidad.
  • app.classloader () es un método Play que devuelve el ClassLoader de la aplicación
  • tools.jar está incluido en mi carpeta lib del proyecto Play (esto implica que está en el classpath del proyecto, de acuerdo con la documentación de Play)

Estoy bastante seguro de que hay algo más que debo hacer antes de que Play pueda cargar la clase del compilador de Java. Simplemente no sé qué me estoy perdiendo.

Conozco opciones como Runtime.exec("javac myFile.java")el compilador Eclipse JDT, pero eso no es lo que estoy buscando.

Ah, y algo así System.setProperty("java.home", "PATH_TO_YOUR_JDK");y luego ToolProvider.getSystemJavaCompiler();funciona, pero encuentro esta solución tan fea.

Atentamente

EDITAR : (para proporcionar información adicional y reflejar el último estado) Esta es una representación básica de la estructura de la aplicación web:

myApp
|-conf\...
|-lib\MyJar.jar
|-lib\tools.jar
|-logs\...
|-...

MyJar.jar ahora tiene un META-INF/MANIFEST.MFarchivo con el siguiente contenido:

Manifest-Version: 1.0
Sealed: true
Main-Class: here.comes.my.main.class
Class-Path: tools.jar

Sin iniciar la aplicación Play, estoy intentando (en la libcarpeta): java -jar MyJar.jar- mi mainmétodo simple intenta invocar el compilador ( ToolProvider.getSystemJavaCompiler();) y regresa null. Esto me lleva a creer que el problema no tiene nada que ver con Play: ¡ni siquiera puedo obtener un compilador cuando normalmente ejecuto mi Jar!

Respuesta 1

No hay diferencia entre las aplicaciones web y las aplicaciones independientes.

No debe empaquetar tools.jar en su classpath de webapp. El cargador de clases en Java generalmente solo funciona de abajo hacia arriba. Por lo tanto, ToolProvider que es parte de jdk no verá su tools.jar en la ruta de clase de la aplicación web (no puede mirar hacia abajo en la ruta de clase de la aplicación web).

Solución: use un JDK y asegúrese de señalarlo o poner tools.jar en un directorio ext de Java. Puede anular el directorio ext configurando la propiedad -Djava.ext.dir en cualquier directorio que desee.

Respuesta: 2

Tengo una clase con un montón de campos, todos privados (subclases acceden a algunos con getters protegidos). Necesito pasar la mayoría de esos campos a un método en otra clase que los formatee y ...

Me gustaría llamar a un método definido como <T> void foo (Class <? Extend Collection <T>>) pero no hay forma de que el compilador me deje pasar foo (ArrayList <Integer> .class); Cuál es el ...

Así que tengo este WebElement (ahora en modo deshabilitado): <select id = "id1" name = "name" disabled = ""> <option value = ""> Seleccione ... </option> <option value = "false "> No </option> <...

Actualmente estoy desarrollando una aplicación de Android que interactúa con un servicio web RESTful. El cliente puede realizar CRUD completo en el servicio web. Después de buscar las mejores prácticas vi Google I / O ...