Até mesmo para os desenvolvedores Java mais ™ fanáticos, o detalhamento da sintaxe pode ser uma desvantagem para a programação de aplicativos nessa linguagem. Embora às vezes seja possível evitar esse detalhamento usando uma linguagem mais nova como o Groovy, em alguns casos o uso de Java é preferível ou até mesmo obrigatório. Portanto, é conveniente experimentar o Projeto Lombok, uma biblioteca de software livre para geração de códigos na plataforma Java.
O Lombok é conveniente porque se encarrega de reduzir o código clichê linha a linha em aplicativos Java, para que você nunca mais precise escrever novamente uma boa parte da sintaxe Java. Entretanto, não é só o "açúcar sintático" que adoça o Lombok — é uma abordagem exclusiva à geração de códigos, juntamente com todas as possibilidades de desenvolvimento Java que ela abre.
Neste artigo, eu apresento o Projeto Lombok e explico por que eu acredito que ele é um acréscimo excelente, mas não perfeito, à caixa de ferramentas do desenvolvedor Java. Apresentarei uma visão geral do Lombok — inclusive de como funciona e para que é usado — e uma lista rápida de seus prós e contras atuais. Em seguida, abordarei um dos casos de uso mais fortes, mas também mais complexos, do Lombok: a extensão uma base de código customizado. Pode ser o seu próprio código ou um padrão Java já existente que ainda não faz parte da biblioteca do Lombok. De uma forma ou de outra, o restante do artigo tratará de dicas e truques para estender o Lombok, incluindo algumas diretrizes para determinar se vale a pena usar as APIs do Lombok ou se, no fim das contas, seria melhor escrever o clichê do seu projeto.
O código de amostra incluído (consulte Download) estende o Lombok para gerar o código clichê de JavaBeans. O código pode ser usado livremente e é licenciado sob o Apache 2.0.
O que torna o Lombok diferente
Talvez a maior razão para usar o Lombok e não outras ferramentas de geração de códigos seja o fato de que o Lombok vai além da simples geração de origens Java ou de bytecode: ele transforma a árvore de sintaxe abstrata (AST), modificando a sua estruturar no tempo de compilação. A AST é uma representação em árvore do código de origem analisado, criada pelo compilador, semelhante ao modelo em árvore do DOM de um arquivo XML. Ao modificar (ou transformar) a AST, o Lombok mantém o seu código de origem limpo e sem excessos, ao contrário do que acontece na geração de códigos com texto simples. O código gerado pelo Lombok também é visível para as classes dentro da mesma unidade de compilação, ao contrário da manipulação direta de bytecode com bibliotecas como CGLib ou ASM.
O Lombok suporta mais de um mecanismo para acionar a geração de códigos, inclusive as anotações Java muito difundidas. O uso das anotações Java permite que os desenvolvedores modifiquem as classes anotadas — algo que o processamento normal da anotação Java proíbe.
Para ver um exemplo do que o Lombok pode fazer, considere a classe da Listagem 1:
Lista 1. Uma classe Java simples
public class Person {
private String firstName;
private String lastName;
private int age;
}
|
Não é difícil incluir implementações de equals, hashCode e toString no seu código — mas esse processo é tedioso e propenso a erros. Você poderia usar um IDE de Java moderno, como o Eclipse, para gerar automaticamente a maior parte do código clichê, mas essa solução seria apenas parcial. Pouparia tempo e esforço, mas prejudicaria a legibilidade e compreensão do código, porque o código clichê geralmente acrescenta ruído à origem do aplicativo.
Entretanto, o Lombok tem uma solução inteligente para o problema do código clichê. Tomando a Listagem 1 como exemplo, é possível gerar facilmente os métodos necessários incluindo a anotação @lombok.Data na classe Person.java . A Figura 1 mostra a geração de códigos do Lombok dentro do Eclipse. Na visualização Outline, é possível ver que os métodos gerados aparecem na classe compile, ao passo que o arquivo de origem permanece livre de clichês.
Figura 1. O Lombok em ação
O Lombok suporta os conhecidos compiladores Java javac e Eclipse Compiler for Java (ECJ). Embora esses dois compiladores produzam uma saída semelhante, a implementação deles é totalmente diferente. Consequentemente, o Lombok vem com dois conjuntos de manipuladores de anotação (o código que "engancha" no Lombok e contém a lógica de geração de códigos): um para cada compilador. Felizmente, isso é transparente — portanto, como usuários, só precisamos lidar com um único conjunto de anotações Java.
O Lombok também fornece uma forte integração ao Eclipse: o salvamento de um arquivo Java aciona automaticamente a geração de códigos do Lombok (sem nenhum atraso perceptível) e atualiza a visualização Outline do Eclipse para mostrar os membros gerados, como mostra a Figura 1.
Para os desenvolvedores que gostam de ver o funcionamento interno, a ferramenta delombok do Lombok, acessada por meio da linha de comando do Ant ou do Maven, será a sua "lanterna". O Delombok toma o código já transformado pelo Lombok e gera arquivos de origem Java simples a partir dele. O código que foi "delombokado" conterá todas as transformações feitas anteriormente pelo Lombok, em texto simples. Por exemplo: se você aplicasse delombok ao código da A Figura 1, veria como equals, hashCode e toString foram implementados de fato.
Ninguém é perfeito: desvantagens do uso do Lombok
Antes de adotar o Lombok e começar a incluí-lo nos seus projetos, deve saber que ele tem algumas limitações. Duas, especificamente, são importantes:
- O ponto forte do Lombok pode ser um ponto fraco . O principal argumento contrário ao Lombok é que ele "faz mágicas demais". Primeiro, ao eliminar parte do detalhamento do código Java, o Lombok alterou uma característica da linguagem que agrada a muitos programadores Java: será impresso exatamente o que está na tela. Com o Lombok, um arquivo.java não mostra o que há em um arquivo .class.
Em segundo lugar, certas transformações do Lombok alteram a sintaxe Java que conhecemos, de forma considerável. A transformação@SneakyThrowsé um bom exemplo disso. Permite lançar exceções verificadas sem declará-las em uma definição de método, como se fossem exceções não verificadas:
Lista 2. @SneakyThrows — muito dissimulado// normally, we would need to declare that this method throws Exception @SneakyThrows public void doSomething() { throw new Exception(); }
- A convenção de nomenclatura das anotações do Lombok não comunica intenção. No Lombok, as anotações deixam de ser apenas metadados: na verdade, atuam como comandos que impulsionam a geração de códigos. Creio que a anotação
@GenerateGettercomunicaria a sua intenção melhor do que a anotação atual de@Getter.
Além desses problemas com o Lombok propriamente dito, também há alguns problemas relacionados à integração ao Eclipse. Em sua maioria, esses problemas ocorrem porque o Eclipse não está ciente da geração de códigos do Lombok:
- O Eclipse lança
NullPointerExceptions de tempos em tempos enquanto gera códigos com o Lombok. A origem do problema ainda é desconhecida. Geralmente, o problema é resolvido ao fechar e reabrir o Eclipse. - A refatoração no Eclipse fica mais difícil com o Lombok. Por exemplo: para renomear um campo que tem getters e setters gerados pelo Lombok usando o Eclipse, é necessário pressionar Alt-Shift-R duas vezes para usar o diálogo Rename Field em vez de renomear o campo no local. Na etapa Preview, é necessário desmarcar getXXX e setXXX a partir do tipo que você está refatorando.
- Como não há uma origem Java para o código gerado pelo Lombok, a depuração fica um pouco confusa. Por exemplo: se você tentar entrar no código de um getter gerado pelo Lombok chamado
getName, o depurador do Eclipse irá para a anotação@Getterdo camponame. Com exceção disso, o depurador do Other funciona normalmente quando o Lombok está presente.
No geral, esses problemas podem ser contornados e, com o tempo, a maioria deles será resolvida pelas equipes de desenvolvimento do Lombok e do Eclipse. Mesmo assim, é com saber no que você está se metendo. Isso se aplica a todas as ocasiões em que você acrescenta uma nova ferramenta à sua caixa de ferramentas.
O Lombok gera a maior parte do código clichê Java comum, inclusive getters, setters, equals e hashCode, só para citar alguns. Isso é útil, mas às vezes é conveniente gerar o seu próprio código clichê. Por exemplo: o Lombok ainda não suporta alguns padrões comuns de codificação, como o JavaBeans. Em alguns casos, talvez também seja necessário gerar um código específico para o seu projeto ou domínio.
O melhor caso de uso, em minha opinião, para estender o Lombok é a prototipagem e a experimentação com novos padrões de código nos estágios iniciais de um projeto. À medida que esses padrões de código amadurecem com o tempo, o Lombok facilita muito a alteração ou o aprimoramento de sua implementação: basta modificar o manipulador da anotação (o código que "engancha" no Lombok para gerar código) e compilar. Toda a base de código será atualizada automaticamente (a não ser que haja mudanças em contratos públicos no código gerado, que provocam erros de compilação). Depois de estabilizar esses padrões de código, você tem a opção de usar delombok no seu código. Desse ponto em diante, é possível trabalhar com a origem Java normal.
Para estender o Lombok, é necessário identificar ou criar uma anotação (ou mais) que acione a geração de códigos do Lombok. Em seguida, você precisa escrever manipuladores de anotação para cada uma das anotações que identificou. O manipulador de anotação é uma classe que implementa duas interfaces do Lombok e a lógica de transformação da AST, — ou seja, geração de códigos.
As seções a seguir contêm recomendações, desde a configuração do projeto até o teste, que podem ser úteis para criar as suas próprias transformações de AST. Também incluí uma amostra de código que demonstra uma extensão funcional do Lombok para o suporte a JavaBeans. Mais sobre esse assunto mais adiante.
O Lombok gera código JavaBeans
Como eu mencionei antes, atualmente o Lombok suporta padrões de código comuns — mas nem todos eles são cobertos, inclusive os JavaBeans. Para demonstrar uma extensão do Lombok, eu escrevi uma amostra rápida de projeto que gera um emaranhado de código JavaBeans. Além de mostrar como estender o Lombok com manipuladores de anotação customizados para javac e ECJ, esse projeto também tem alguns utilitários úteis (como um construtor de método e campo para os dois compiladores) que deixa o processo bem mais limpo e simples.
Eu usei o Eclipse 3.6 (Helios) e uma captura instantânea do repositório git do Lombok para a versão 0.10-BETA2. O código consiste em manipuladores de anotação que geram setters "ligados" de JavaBean. O arquivo zip anexo (consulte a seção Download ) contém o seguinte:
- Um arquivo de construção Ant
- As anotações
@GenerateBoundSettere@GenerateJavaBean - Os manipuladores de anotações (para javac e ECJ) que geram setter "ligado""
- Um pouco de código clichê JavaBeans (por exemplo: a geração de um campo
PropertyChangeSupport)
O código anexo é totalmente funcional e é licenciado sob a licença Apache 2.0. É possível obter uma versão atualizada do código do GitHub (consulte Recursos). Para se inspirar, veja o que o código pode fazer.
Se eu escrever o código da Listagem 3, o Lombok gerará algo semelhante ao código da Listagem 4, usando os meus manipuladores de anotação:
Lista 3. Lombok! Gere JavaBean!
@GenerateJavaBean
public class Person {
@GenerateBoundSetter private String firstName;
}
|
Lista 4. Exemplo de código de suporte para JavaBean que foi gerado
public class Person {
public static final String PROP_FIRST_NAME = "firstName";
private String firstName;
private PropertyChangeSupport propertySupport = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertySupport.removePropertyChangeListener(listener);
}
public void setFirstName(String value) {
String oldValue = firstName;
firstName = value;
propertySupport.firePropertyChange(PROP_FIRST_NAME, oldValue, firstName);
}
}
|
Veja o arquivo readme.txt incluído no código de amostra , referente às instruções para gerar um projeto Eclipse a partir do arquivo de construção do código de amostra.
Em minha opinião, por enquanto, toda extensão do Lombok deve suportar javac e ECJ. O javac é o compilador padrão usado pelas ferramentas de construção como Ant e Maven. Entretanto, na época em que este artigo foi escrito, o Eclipse fornecia uma experiência de edição de código mais suave quando usado em conjunto com o Lombok. O suporte aos dois compiladores é fundamental para a produtividade dos desenvolvedores.
O javac e o ECJ trabalham com uma estrutura de AST semelhante. Infelizmente, eles são implementados de forma muito diferente — e isso obriga você a escrever dois manipuladores de anotação por anotação, um para o javac e um para o ECJ. A boa notícia é que a equipe do Lombok já está trabalhando em uma API unificada da AST — o que, no final, permitirá o desenvolvimento de um único manipulador de anotação por anotação, que funciona com os dois compiladores (consulte Recursos).
Estudando o código de origem do Lombok
A próxima coisa a fazer é ver no que você está se metendo; para fazer isso, não há nada melhor que o código de origem.
O Lombok usa APIs não públicas no javac e no ECJ para realizar a sua técnica inteligente de geração de códigos. Já que o seu código será conectado ao Lombok, é muito provável que precise usar APIs semelhantes ou as mesmas APIs.
O principal problema das APIs não públicas é a falta de documentação e estabilidade. Felizmente, de acordo com a equipe do Lombok, eles não tiveram nenhum problema de portabilidade com as novas versões do Eclipse (veremos o que acontecerá quando o Java 7 for lançado). No momento, a falta de documentação é o maior problema com o qual você tem que lidar. Além disso, mesmo com uma boa documentação, o aprendizado das APIs de dois compiladores diferentes é difícil e demorado. Precisamos de um "guia rápido e prático" do javac e do ECJ — algo que está fora do escopo deste artigo.
A boa notícia é que a equipe do Lombok documentou razoavelmente bem o uso do javac e do ECJ para gerar nós de AST. Eu recomendo enfaticamente a leitura do código deles. Eles trataram dos casos de uso mais comuns: coisas como declarações de variáveis, implementações de método, etc. Ler o código de origem do Lombok é a forma mais rápida de aprender as APIs do javac e do ECJ. A Listagem 5 mostra um exemplo do código de origem do Lombok:
Lista 5. Gerando variáveis locais com o Javac
/* final int PRIME = 31; */ {
if (!fields.isEmpty() || callSuper) {
statements.append(maker.VarDef(maker.Modifiers(Flags.FINAL),
primeName, maker.TypeIdent(Javac.getCTCint(TypeTags.class, "INT")),
maker.Literal(31)));
}
}
|
Como se pode ver, a equipe do Lombok documentou o que cada bloco de código gera. Na próxima vez que você precisar gerar a declaração de uma variável local, poderá voltar para essa origem e usá-la como referência.
Não se limite a ler apenas os arquivos .java do Lombok. Os desenvolvedores do Lombok também forneceram boas indicações para configurar e desenvolver o projeto e para testar os manipuladores de anotação. Tratarei desses tópicos mais detalhadamente nas seções a seguir.
Depois de experimentar o gerenciamento automático de dependência nos seus projetos, é muito difícil voltar e fazer isso manualmente. O mundo do Java tem mais de uma ferramenta de construção que fornece gerenciamento de dependência, incluindo o Ivy e o Maven (consulte Recursos). Entretanto, ao criar extensões do Lombok, as opções se restringem a uma — o Ivy.
Um dos motivos para escolher o Ivy é que todas as dependências necessárias, como o javac, estão no armazenador central do Maven — o que exclui o Maven. A outra razão é que o Ivy suporta o gerenciamento de dependências que não estão em um repositório do Maven. É fácil especificar um link pelo qual se pode transferir uma dependência por download. Essa configuração requer um arquivo de configuração customizado ivysettings.xml, o que não é grande coisa.
O Ivy se baseia no Ant, fornecendo o gerenciamento de dependência para a sua construção. A equipe do Lombok usa uma versão melhorada do Ivy que eles mesmos desenvolveram — o ivyplusplus (consulte Recursos). Essa extensão do Ivy fornece algumas metas úteis do Ant, como criar arquivos de projeto Eclipse e IntelliJ a partir de uma lista de dependências.
Para configurar o projeto de extensão do Lombok, você precisa dos seguintes arquivos:
- arquivo build.xml : um arquivo de construção do Ant que:
- Faz o download do ivyplusplus (a partir de um local especificado) na primeira vez que uma construção é chamada.
- Especifica onde o arquivo de configuração do Ivy está.
- Compila, testa e empacota o código.
- Arquivo buildScripts/ivy.xml : especifica as dependências do projeto.
- Arquivo buildScripts/ivysettings.xml : especifica os repositórios (Maven ou apenas URLs) para obter as dependências.
- Pasta buildScripts/ivy-repo : contém um arquivo XML para cada dependência especificada em ivy.xml. Esses arquivos XML descrevem um artefato de dependência (por exemplo: um local a partir do qual ele pode ser transferido por download, página inicial, etc.)
Não é necessário reinventar a roda. Para poupar tempo e esforço, dê uma olhada nos arquivos de construção do Lombok ou da origem anexa a este artigo e copie/cole os trechos necessários.
Como eu mencionei antes, as anotações do Lombok poderiam comunicar melhor o fato de serem mais do que simples metadados. Devem indicar que são responsáveis pelo acionamento de algum tipo de geração de códigos. Portanto, é altamente recomendado que você pré-anexe todas as anotações relacionadas Lombok com "Generate." No código de origem deste artigo, eu dei às anotações que acionam código de origem relacionado ao JavaBeans os nomes @GenerateBoundSetter e @GenerateJavaBean. Essa convenção de nomenclatura, ao menos, dá aos desenvolvedores que não estão familiarizados com a sua base de código uma indicação de que em algum ponto do seu ambiente de construção há um processo para a geração de código.
Documentando transformações de AST
A documentação é fundamental para a extensão do Lombok. A documentação dos seus manipuladores de anotação beneficiará aos mantenedores das transformações de AST, ao passo que a documentação das anotações beneficiará aos usuários.
Documentando manipuladores de anotação
O código que usa APIs de javac ou ECJ não é fácil de ler e entender. É complexo e longo, até mesmo quando gera o código Java mais simples. A documentação dos manipuladores de anotação facilitará muito a manutenção para você e a sua equipe. Em termos de documentação, constatei que é útil ter o seguinte:
- Um comentário de Javadoc no nível de classe que explica, de modo geral, qual código o manipulador da anotação gera. Acredito que a forma mais fácil de explicar qual código é gerado é incluir um código de amostra no comentário, como mostra a Listagem 6:
Lista 6. Javadoc no nível de classe de um manipulador de anotação/** * Instructs lombok to generate the necessary code to make an annotated Java * class a JavaBean. * <p> * For example, given this class: * * <pre> * @GenerateJavaBean * public class Person { * * } * </pre> * our lombok annotation handler (for both javac and eclipse) will generate * the AST nodes that correspond to this code: * * <pre> * public class Person { * * private PropertyChangeSupport propertySupport * = new PropertyChangeSupport(this); * * public void addPropertyChangeListener(PropertyChangeListener l) { * propertySupport.addPropertyChangeListener(l); * } * * public void removePropertyChangeListener(PropertyChangeListener l) { * propertySupport.removePropertyChangeListener(l); * } * } * </pre> * </p> * * @author Alex Ruiz */
- Comentários normais, não de Javadoc, na base de código para explicar o que o bloco de código gera, como mostra a Listagem 7:
Lista 7. Documentando o que um bloco de código gera// public void setFirstName(String value) { // final String oldValue = firstName; // firstName = value; // propertySupport.firePropertyChange(PROP_FIRST_NAME, oldValue, // firstName); // } JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); long mods = toJavacModifier(accessLevel) | (fieldDecl.mods.flags & STATIC); TreeMaker treeMaker = fieldNode.getTreeMaker(); List<JCAnnotation> nonNulls = findAnnotations(fieldNode, NON_NULL_PATTERN); return newMethod().withModifiers(mods) .withName(setterName) .withReturnType(treeMaker.Type(voidType())) .withParameters(parameters(nonNulls, fieldNode)) .withBody(body(propertyNameFieldName, fieldNode)) .buildWith(fieldNode);
A inclusão de um comentário de Javadoc no nível da classe, semelhante ao que usamos para o manipulador de anotação (na Listagem 6) ajuda os usuários das suas anotações a saber e entender o que acontecerá quando eles consumirem essas anotações.
Consistência entre compiladores
Essa dica só será útil se você optar por suportar javac e ECJ. Quando você tem dois conjuntos de manipuladores de anotação, qualquer correção de erro, alteração ou inclusão deve ser aplicada aos dois conjuntos (ou ramificações). Quanto maior a semelhança das ramificações, mais fáceis e rápidas serão as mudanças. Essa semelhança deve ocorrer no nível do pacote e no nível do arquivo.
Consistência no nível do pacote: na medida do possível, cada ramificação (javac e ECJ) deve ter o mesmo número de classes, usando o mesmo nome, como mostra a Figura 2:
Figura 2. Semelhanças de pacotes entre as ramificações do javac e do ECJ
Consistência no nível do arquivo: como as duas ramificações terão um número semelhante de classes com nomes semelhantes, o conteúdo de cada par de arquivos com o mesmo nome deve ser o mais semelhante possível: os campos, contagem de métodos, nomes de métodos, etc. devem ser quase iguais. A Listagem 8 mostra o método generatePropertySupportField referente ao javac e ao ECJ. Observe que, embora as APIs de AST sejam diferentes, a implementação desses métodos é muito semelhante.
Lista 8. Comparando os manipuladores de anotação do javac e do ECJ
// javac
private void generatePropertyChangeSupportField(JavacNode typeNode) {
if (fieldAlreadyExists(PROPERTY_SUPPORT_FIELD_NAME, typeNode)) return;
JCExpression exprForThis = chainDots(typeNode.getTreeMaker(), typeNode, "this");
JCVariableDecl fieldDecl = newField().ofType(PropertyChangeSupport.class)
.withName(PROPERTY_SUPPORT_FIELD_NAME)
.withModifiers(PRIVATE | FINAL)
.withArgs(exprForThis)
.buildWith(typeNode);
injectField(typeNode, fieldDecl);
}
// ECJ
private void generatePropertyChangeSupportField(EclipseNode typeNode) {
if (fieldAlreadyExists(PROPERTY_SUPPORT_FIELD_NAME, typeNode)) return;
Expression exprForThis = referenceForThis(typeNode.get());
FieldDeclaration fieldDecl = newField().ofType(PropertyChangeSupport.class)
.withName(PROPERTY_SUPPORT_FIELD_NAME)
.withModifiers(PRIVATE | FINAL)
.withArgs(exprForThis)
.buildWith(typeNode);
injectField(typeNode, fieldDecl);
}
|
Testando as transformações de AST
O teste das transformações de AST customizadas é muito mais simples do que você pensa, graças à infraestrutura de teste que o Lombok estabeleceu. Para demonstrar como é fácil testar transformações de AST, vamos começar com as etapas de teste JUnit na Listagem 9:
Lista 9. Teste de unidade para todos os manipuladores de anotação do ECJ
import static lombok.DirectoryRunner.Compiler.ECJ;
import java.io.File;
import lombok.*;
import lombok.DirectoryRunner.Compiler;
import lombok.DirectoryRunner.TestParams;
import org.junit.runner.RunWith;
/**
* @author Alex Ruiz
*/
@RunWith(DirectoryRunner.class)
public class TestWithEcj implements TestParams {
@Override public Compiler getCompiler() {
return ECJ;
}
@Override public boolean printErrors() {
return true;
}
@Override public File getBeforeDirectory() {
return new File("test/transform/resource/before");
}
@Override public File getAfterDirectory() {
return new File("test/transform/resource/after-ecj");
}
@Override public File getMessagesDirectory() {
return new File("test/transform/resource/messages-ecj");
}
}
|
Esse teste funciona mais ou menos da seguinte forma:
- O teste compila todos os arquivos Java da pasta especificada por
getBeforeDirectory, usando o compilador especificado porgetCompiler) e pelo Lombok. - Após a compilação, o teste cria uma representação em texto das classes compiladas usando o
delombok. - O teste lê os arquivos a partir da pasta especificada em
getAfterDirectory. Esses arquivos contêm o conteúdo esperado das classes compiladas. O teste compara o conteúdo desses arquivos com a origem obtida [na Etapa 2]. Os arquivos a ser comparados devem ter o mesmo nome. - O teste lê os arquivos a partir da pasta especificada em
getMessagesDirectory. Esses arquivos contêm as mensagens esperadas do compilador (avisos e erros). O teste compara o conteúdo desses arquivos com as mensagens reais mostradas durante a compilação, se houver. Não é necessário ter um arquivo de mensagens se, para a compilação de um arquivo Java, não há mensagens esperadas. A correspondência é estabelecida pelo nome. Por exemplo: se há mensagens do compilador esperadas ao compilarCompleteJavaBean.java, o arquivo que contém essas mensagens deve ter o nomeCompleteJavaBean.java.messages. - Se todas as saídas esperadas correspondem às reais, ocorre a aprovação no teste; do contrário, ocorre a reprovação.
Como se pode ver, esta é uma forma muito diferente, mas efetiva, de testar os manipuladores de anotação:
- Há um teste JUnit por compilador (javac e ECJ) em vez de um teste JUnit por manipulador de anotação.
- Em vez de ter um método de teste por caso de uso, temos um arquivo de texto que contém o código gerado esperado e um arquivo de texto opcional que contém as mensagens esperadas do compilador.
- Para os testes, não importa como as APIs do javac e do ECJ estão sendo usadas. Os testes garantem que código gerado esteja correto.
O teste que eu descrevi é bom para garantir que os manipuladores de anotação geram o código que você espera. Mesmo assim, é necessário testar para ver se o código gerado realmente faz o que você espera que ele faça. Para verificar a correção do comportamento do código gerado, é necessário escrever classes Java que usam as suas transformações de AST e, em seguida, escrever testes que verificam o comportamento do código gerado. Basicamente, você testará o código como se ele tivesse sido escrito por você.
A forma mais fácil de compilar e executar esses testes é usar o Ant — o que significa compilar com o javac. Como você já testou e sabe que o código gerado por meio do ECJ está correto, creio que não seja necessário executar esses testes dentro do Eclipse (o que pode complicar muito a configuração).
Incluí testes para manipuladores de anotação do javac e do ECJ no código de amostra deste artigo (consulte Download).
O Projeto Lombok é uma ferramenta potente que reduz o detalhamento do código Java. Esse objetivo é alcançado por meio de alguns usos inteligentes e incomuns das anotações Java e APIs dos compiladores. Como qualquer ferramenta, ele não é perfeito. Os ganhos (código mais curto e limpo) têm um custo: o código Java perde a sensação de WYSIWYG e os desenvolvedores perdem parte da funcionalidade do IDE que nós amamos. Antes de incluir o Lombok na sua caixa de ferramentas, pese os prós e contras e determine por si mesmo se os ganhos compensam as perdas.
Se optar por usar o Lombok, é possível que você queira estendê-lo para gerar o seu próprio código clichê. Atualmente, estender o Lombok não é uma tarefa fácil e não é para qualquer um, mas é algo factível. Este artigo apresentou algumas diretrizes relacionadas a quando se deve estender o Lombok e descreveu como fazer isso. Cabe a você determinar se vale a pena empregar tempo e esforço para estender o Lombok em vez de simplesmente escrever o código clichê à mão.
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Source code for this article1 | j-lombok.zip | 63KB | HTTP |
Informações sobre métodos de download
Nota
- Pode-se encontrar uma versão atualizada do código de origem no github.
Aprender
- "Eliminate Java verbosity the easy way" (Brian M. Carey, developerWorks, fevereiro de 2010): outra oportunidade de estudar exemplos funcionais e ver a geração de códigos do Lombok em ação. Esse artigo também dá mais detalhes sobre a instalação do Lombok.
- "Common Java Object Functionality with Project Lombok" (Dustin Marx, Cogitations and Speculations, setembro de 2010): uma introdução breve e excelente que inclui um resumo dos artigos e outras mídias que estão relacionados ao Lombok.
- Projeto
Lombok: visite a página inicial do projeto Lombok.
- Lista de e-mails do projeto Lombok: conheça as novidades do Lombok.
- lombok.ast: a página inicial do projeto referente à API Unified AST para o Lombok.
- OpenJDK: home do javac.
- Eclipse.org: visite a página inicial do Eclipse para saber mais sobre o ECJ.
-
Navegue pela livraria da tecnologia Java para ver livros sobre este e outros tópicos técnicos.
-
Zona tecnologia Java do developerWorks: Encontre centenas de artigos sobre quase todos os aspectos da programação Java.
Obter produtos e tecnologias
- Apache Ivy: saiba mais sobre o Ivy e faça o download.
- Ivyplusplus: obtenha uma versão melhorada do Ivy, desenvolvida pela equipe do Lombok.
Discutir
- Participe da comunidade do developerWorks. Entre em contato com outros usuários do developerWorks, enquanto explora os blogs, fóruns, grupos e wikis orientados ao desenvolvedor.

Alex Ruiz gosta de ler qualquer coisa que esteja relacionada ao desenvolvimento de Java, programação orientada a objetos, design de APIs e teste. A programação é o seu primeiro amor. Alex é o criador da FEST, uma biblioteca Java inovadora que tem o objetivo de facilitar os testes de UI e testes em geral. Alex trabalha na Google. Confira o blog do Alex