Especifique o caminho de saída para Dynamic Compilation
-
19-09-2019 - |
Pergunta
Meu compilação dinâmica em Java 6 está funcionando perfeitamente. No entanto, eu gostaria de mudar o caminho de saída. Eu tentei toneladas de coisas (vou poupá-lo) sem sucesso. De qualquer forma, aqui está o código de trabalho
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());
Mas a saída vai para o diretório de origem, o que não é o que eu quero.
Eu suspeito que a resposta pode estar na compiler.getTask
mas a API não é muito explícito quanto ao que alguns dos parâmetros poderia significar. Ou talvez algo com o gerenciador de arquivos. Eu tentei
fileManager.setLocation(StandardLocation.locationFor("testFiles2"), null);
mas, novamente, supondo que provavelmente não é uma boa idéia.
Obrigado!
Editar: Eu tentei usar opções, também, como este (desculpe se há uma maneira mais 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();
}
};
e, em seguida, passar as opções para getTask, mas a mensagem de erro é "bandeira inválido."
Solução
Código no primeiro post iria funcionar, mas o seguinte get de erro é jogado:
java.lang.IllegalArgumentException: invalid flag: -d folder
Isto porque, passando "-d folder"
faz com que o analisador acho que analisar uma opção. As opções devem ser separadas como "-d", "folder"
.
Exemplo de aplicação seguintes:
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();
Outras dicas
Eu estava enfrentando o mesmo problema hoje.
A resposta (usando o método getTask
regular em vez de `run) é especificar o dir de saída no FileManager:
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(outputDir));
E é isso !! :)
A documentação é um pouco enganosa, quer dizer, uma amostra poderia vir muito útil. Mas eventualmente ele me levou lá.
Editar
Aqui está um exemplo em execução:
// 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();
Eu tenho 0 experiência com as ferramentas de compilação dinâmica Java 6. Mas ninguém respondeu:)
A tarefa de compilação obtém um objeto FileManager
. Se você usar o padrão, então classes são geradas na árvore de diretório de origem. O que você poderia fazer é fornecer sua própria subclasse FileManager com um método getFileForOutput
substituído. A descrição API de getFileForOutput indica que isso irá influenciar onde a sua saída (= classe) arquivos irá.
Atualizar
Como ligar os gerenciadores de arquivos
ForwardingJavaFileManager, ForwardingFileObject e ForwardingJavaFileObject Subclassing não está disponível para substituir o comportamento de um gerenciador de arquivos padrão como ele é criado por chamar um método em um compilador, não invocando um construtor. Em vez de encaminhamento (ou delegação) deve ser usado. Essas classes torna mais fácil de transmitir a maioria das chamadas para um determinado gerenciador de arquivos ou objeto de arquivo, permitindo comportamento personalizando. Por exemplo, considere como para registrar todas as chamadas para 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();
Update 2
I ler sobre a compilação dinâmica e construí meu próprio aplicativo para fazer isso. Este código contém um pouco demais cerimônia (ou seja, ele pode ser simplificado) mas 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());
}
}
}
Eu não tenho certeza de como obter este código para trabalhar com uma lista gerada dinamicamente de arquivos Java; Eu provavelmente apenas fazer compiler.run
separadamente para cada arquivo-fonte.