Substituição de código com um processador de anotação

Eu estou tentando escrever um processador de anotação para inserir methods e campos em uma class … e a documentação é tão escassa. Não estou indo muito longe e não sei se estou me aproximando corretamente.

O ambiente de processamento fornece um object Filer que possui methods úteis para criar novos arquivos de origem e de class. Eles funcionam bem, mas depois tentei descobrir como ler os arquivos de origem existentes e tudo o que ele fornece é “getResource”. Então, na implementação do meu processador eu fiz isso:

 @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { try { for (TypeElement te : annotations) { for (Element element : roundEnv.getElementsAnnotatedWith(te)) { FileObject in_file = processingEnv.getFiler().getResource( StandardLocation.SOURCE_PATH, "", element.asType().toString().replace(".", "/") + ".java"); FileObject out_file = processingEnv.getFiler().getResource( StandardLocation.SOURCE_OUTPUT, "", element.asType().toString().replace(".", "/") + ".java"); //if (out_file.getLastModified() >= in_file.getLastModified()) continue; CharSequence data = in_file.getCharContent(false); data = transform(data); // run the macro processor JavaFileObject out_file2 = processingEnv.getFiler().createSourceFile( element.asType().toString(), element); Writer w = out_file2.openWriter(); w.append(data); w.close(); } } } catch (Exception e) { e.printStackTrace(); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); } return true; } 

Meu primeiro dilema é que não posso deixar de sentir que element.asType().toString().replace(".", "/") + ".java" (para obter o nome do tipo qualificado e convertê-lo em um pacote e caminho do arquivo de origem) não é uma boa maneira de abordar o problema. O restante da API é superprojetado, mas não parece ser um método prático para recuperar o código-fonte original.

O problema real é que, em seguida, o compilador fica perturbado espontaneamente pelo segundo arquivo de origem no diretório de saída (“erro: class duplicada”) e agora estou preso.

Eu já escrevi o resto disso – um lexer e analisador de macro e outras coisas para calcular alguns dados e inserir os valores e methods de campo – mas ele funciona como uma etapa inicial fora do compilador. Exceto pelo fato de que os arquivos originais não podem ter uma extensão .java (para evitar que o compilador os veja), isso funciona muito bem. Então ouvi dizer que as annotations podem gerar código, o que, presumo, será mais adequado e conveniente, mas não consigo encontrar muita orientação sobre isso.

A intenção por trás do processador de anotação é permitir que um desenvolvedor adicione novas classs, não substitua as classs existentes. Dito isto, há um bug que permite adicionar código a classs existentes. O projeto Lombok aproveitou isso para adicionar getter e setter (entre outras coisas) às suas classs java compiladas.

A abordagem que tomei para ‘replace’ methods / campos é estender de ou delegar para a class de input. Isso permite que você substitua / desvie as chamadas para a class alvo.

Então, se esta é sua class de input:

InputImpl.java:

 public class InputImpl implmements Input{ public void foo(){ System.out.println("foo"); } public void bar(){ System.out.println("bar"); } } 

Você pode gerar o seguinte para “replace”:

InputReplacementImpl.java:

 public class InputReplacementImpl implmements Input{ private Input delegate; //setup delegate.... public void foo(){ System.out.println("foo replacement"); } public void bar(){ delegate.bar(); } } 

Isso levanta a questão, como você faz referência a InputReplacementImpl vez de InputImpl . Você pode gerar mais algum código para realizar o agrupamento ou simplesmente chamar o construtor do código esperado para ser gerado.

Não sei bem qual é a sua pergunta, mas espero que isso lance alguma luz sobre seus problemas.

Intereting Posts