2010-01-08 15 views
6

Mi compilación dinámica en Java 6 funciona perfectamente. Sin embargo, me gustaría cambiar la ruta de salida. He intentado toneladas de cosas (te ahorraré) en vano. De todos modos, aquí está el código de trabajoEspecifique la ruta de salida para la compilación dinámica

String[] filesToCompile = { "testFiles/Something.java" }; 
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(filesToCompile); 
CompilationTask task = compiler.getTask(null, fileManager, null,null, null, compilationUnits); 
System.out.println("Good? " + task.call()); 

Pero la salida va al directorio de origen, que no es lo que quiero.

Sospecho que la respuesta puede estar en el compiler.getTask pero la API no es muy explícita en cuanto a lo que algunos de los parámetros pueden significar. O tal vez algo con el administrador de archivos. He intentado

fileManager.setLocation(StandardLocation.locationFor("testFiles2"), null); 

pero de nuevo, adivinando probablemente no es una buena idea.

Gracias!

Editar: He intentado usar opciones, también, como esto (lo siento si hay una manera más compacta):

final List<String> optionsList = new ArrayList<String>(); 
    optionsList.add("-d what"); 
    Iterable<String> options = new Iterable<String>() {   
     public Iterator<String> iterator() { 
      return optionsList.iterator(); 
     } 
    }; 

y luego pasar las opciones a getTask, pero el mensaje de error es "no válida Bandera."

+0

+1 por hacerme consciente de que existe una cosa tal como la compilación dinámica ahora! –

+0

¡Siempre lo hubo, ahora está incorporado! –

+0

Mi respuesta fue actualizada. –

Respuesta

5

Código en el primer post iba a funcionar, pero arrojado el siguiente de get error:

java.lang.IllegalArgumentException: invalid flag: -d folder 

Esto se debe a que al pasar "-d folder" hace que el analizador piense que está analizando una opción. Las opciones se deben separar como "-d", "folder".

Ejemplo de trabajo siguiente:

JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 
StandardJavaFileManager sjfm = javaCompiler.getStandardFileManager(null, null, null); 

String[] options = new String[] { "-d", "output" }; 
File[] javaFiles = new File[] { new File("src/gima/apps/flip/TestClass.java") }; 

CompilationTask compilationTask = javaCompiler.getTask(null, null, null, 
     Arrays.asList(options), 
     null, 
     sjfm.getJavaFileObjects(javaFiles) 
); 
compilationTask.call(); 
+0

¿qué pasa con rutas como "c: \\ foo bar \\ foo" o "c:/foo bar/foo"? ¿Se pueden analizar correctamente los espacios en blanco o las barras diagonales? – Gobliins

+0

No lo sé, pero supongo que no es necesario escapar, ya que los argumentos ahora se pasan correctamente (y porque la naturaleza del problema original era exactamente la de los parámetros que no se analizan por separado). Intenta informar? – Gima

4

Tengo 0 experiencia con las herramientas del compilador dinámico Java 6. Pero nadie más ha respondido :)

La tarea de compilación obtiene un objeto FileManager. Si usa el estándar, las clases se generan en el árbol del directorio de origen. Lo que podría hacer es proporcionar su propia subclase FileManager con un método getFileForOutput reemplazado. La descripción API de getFileForOutput indica que esto influirá en dónde irán sus archivos de salida (= clase).

actualización

Cómo conectar los administradores de archivos

ForwardingJavaFileManager, ForwardingFileObject y ForwardingJavaFileObject subclases no está disponible para anular el comportamiento de un administrador de archivos estándar, ya que se crea llamando a una método en un compilador, no invocando un constructor. En cambio, se debe usar el reenvío (o delegación). Estas clases facilitan reenviar la mayoría de las llamadas a un gestor de archivos o un objeto de archivo dado mientras permiten el comportamiento de personalización. Por ejemplo, considere la forma de registrar todas las llamadas a JavaFileManager.flush():

final Logger logger = ...; 
    Iterable<? extends JavaFileObject> compilationUnits = ...; 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null); 
    JavaFileManager fileManager = new ForwardingJavaFileManager(stdFileManager) { 
     public void flush() { 
      logger.entering(StandardJavaFileManager.class.getName(), "flush"); 
      super.flush(); 
      logger.exiting(StandardJavaFileManager.class.getName(), "flush"); 
     } 
    }; 
    compiler.getTask(null, fileManager, null, null, null, compilationUnits).call(); 

Actualización 2

leí arriba en la compilación dinámica y construido mi propia aplicación para hacer esto. Este código contiene demasiada ceremonia (es decir, podría simplificarse) ¡pero funciona!

package yar; 

import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 

public class DynamicCompiler { 

    JavaCompiler compiler; 

    public DynamicCompiler() { 
     this.compiler = ToolProvider.getSystemJavaCompiler(); 
     if (this.compiler == null) { 
     throw new NullPointerException("Cannot provide system compiler."); 
     } 
    } 

    public void compile() { 
     this.compiler.run(null, System.out, System.err, 
      "-d", "testFiles2", 
      "testFiles/Hello1.java", "testFiles/Hello2.java"); 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     try { 
     DynamicCompiler dc = new DynamicCompiler(); 
     dc.compile(); 
     } catch (Exception e) { 
     System.err.println(e.getMessage()); 
     } 
    } 

} 

No estoy seguro de cómo hacer que este código funcione con una lista de archivos Java generada dinámicamente; Probablemente solo haga compiler.run por separado para cada archivo fuente.

+0

Esto podría ser cierto, pero desafortunadamente getJavaFileObjects está solo en el StandardJavaFileManager ... Veré qué se puede hacer de todos modos. Si esto fuera Ruby, tu respuesta sería suficiente para el parche del mono y listo :) –

+0

En Java, el camino a seguir es crear subclases ... 'ForwardingJavaFileManager' implementa' StandardJavaFileManager' y ese es el que usarías. –

+0

De hecho, tiene un constructor que puede ajustar alrededor del FileManager que obtendría de 'compilador'. Por supuesto, querrás hacer que ese constructor sea público en tu clase derivada. –

8

Hoy tuve el mismo problema.

La respuesta (utilizando el método regular getTask en lugar de `run) es especificar el directorio de salida en el Gestor de archivos:

fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputDir)); 

Y eso es todo !! :)

La documentación es un poco engañosa, es decir, una muestra podría ser muy útil. Pero finalmente me llevó allí.

EDITAR

He aquí una muestra de reproducción:

// write the test class 
    File sourceFile = new File("First.java"); 
    FileWriter writer = new FileWriter(sourceFile); 

    writer.write(
      "package load.test;\n" + 
      "public class First{}" 
    ); 
    writer.close(); 

    // Get the java compiler for this platform 
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(
      null, 
      null, 
      null); 

    //--   H E R E --// 
    // Specify where to put the genereted .class files 
    fileManager.setLocation(StandardLocation.CLASS_OUTPUT, 
          Arrays.asList(new File("/tmp"))); 
    // Compile the file 
    compiler 
     .getTask(null, 
       fileManager, 
       null, 
       null, 
       null, 
       fileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile))) 
     .call(); 
    fileManager.close(); 

    // delete the file 
    sourceFile.deleteOnExit(); 
+0

Ha pasado un tiempo desde que miré este problema. ¿Entonces estás diciendo que tu respuesta realmente resuelve todo el problema? –

+0

¡Yeap! ¡Bastante! Actualizaré la respuesta con una muestra – OscarRyz

+0

Funciona bien: igual que usar "-d" en el parámetro de opciones getTask(), pero más limpio. – Atorian

Cuestiones relacionadas