Anotações no J2SE 5.0
Um novo paradigma de programação em Java
Em artigos anteriores, já apresentamos todas as novas funcionalidades do Tiger (J2SE 5.0) e dedicamos um artigo inteiro aos Tipos Genéricos (Edição 16). Continuando a maratona, vamos aplicar nossa lente de aumento sobre outra novidade de grande calibre do Java 5: Anotações.
Isso não esgotará este formidável release do Java; ainda há muitos assuntos a cobrir mas estes são, na maioria, itens especializados, que interessam apenas a alguns desenvolvedores e aplicações. Por exemplo, as novas APIs de New I/O são excelentes para quem precisa, mas são somente uma curiosidade para boa parte dos programadores Java – algo como “é bom saber que essa API existe... para que os caras que implementam meu servidor de aplicações possam fazer isso bem”.
Já as anotações, assim como os tipos genéricos, irão transformar completamente a rotina de todos os desenvolvedores Java, mais cedo ou mais tarde. Mesmo quem não for “convertido” imediatamente será logo arrastado de roldão pelo suporte a essas duas facilidades, que foi acrescentado a uma variedade de novas APIs. A maioria das JSRs que estão em tramitação atualmente, e as que ainda virão, exploram tipos genéricos e anotações sempre que isso fizer sentido.
Para utilizar qualquer uma dessas novas APIs – e não estamos falando de qualquer API, mas das novas versões das APIs de XML, Web Services, Servlets e EJB, por exemplo – você terá que se familiarizar com tipos genéricos e anotações.
No entanto, isso pode ser feito gradualmente. Para usar uma nova API, será preciso saber como declarar e utilizar tipos genéricos e anotações, mas não necessariamente como criar novos tipos genéricos ou novas anotações. Em ambos os casos, você pode começar somente como “consumidor” e, após adquirir experiência e segurança, tornar-se também um “produtor” de software com as novas características. É um bom caminho de adoção e de migração para as novas tecnologias.
Evolução e compatibilidade
Uma questão que fica no ar é quanto à compatibilidade de todas essas novas APIs com versões anteriores do J2SE. A Sun e o JCP sempre foram bastante conservadores, criando novos recursos que não exigiam a última palavra em versão do J2SE. Por exemplo, a JSR-154 (Servlet 2.4) só exige o J2SE 1.3, muito embora o J2SE 1.4 já estivesse disponível (recém-lançado) quando a JSR começou e já fosse uma plataforma extremamente madura quando, após quase dois anos, essa JSR chegou ao Final Release. Muita gente reclamou da falta de suporte direto a New I/O e de outras coisas que não foram feitas, somente para preservar compatibilidade com o J2SE 1.3.
Agora tudo isso mudou. Toda uma leva de APIs que hoje estão no forno exigem como plataforma J2SE mínima a versão 5.0, que ainda nem está disponível (estaremos na fase Release Candidate quando esta edição for publicada). Essas APIs pioneiras foram desenvolvidas junto com o J2SE 5.0; foram sendo especificadas utilizando funcionalidades que também estavam em gestação, nas inúmeras JSRs componentes do J2SE 5.0. Isso exigiu muitas conversas cruzadas entre membros dos diversos grupos de trabalho; também exigiu um “voto de fé” no Tiger, já que a adoção de todas as novas APIs fica amarrada à adoção da nova versão do J2SE.
Mais do que qualquer anúncio de imprensa da Sun, isso evidencia o Tiger como o mais importante release do Java, no mínimo desde o Java 2 (1.2), talvez até mais. Não é somente a JVM e suas APIs núcleo. Todo o “ecossistema” de especificações, APIs e produtos vão entrar numa nova geração, de uma vez só, e amarrados.
Isso será uma dificuldade para algumas empresas e ambientes, que devido ao comportamento histórico da Sun, habituaram-se a ser ainda mais conservadores. Até hoje sou obrigado a manter compatibilidade com J2SE 1.3 (!) em projetos para clientes que ainda não homologaram ambientes de servidores de aplicações baseados no J2SE 1.4 (e este já tem mais de dois anos). Mas essas empresas serão obrigadas a mudar de comportamento, se não quiserem ser excluídas dos benefícios de praticamente todos os aperfeiçoamentos na tecnologia Java a partir deste momento.
Colocando tudo isso em perspectiva, podemos avaliar melhor os “sacrifícios” que o próprio Tiger faz em nome da compatibilidade. Já comentei essas coisas em artigos anteriores; por exemplo, os Tipos Genéricos do Java não realizam todos os sonhos dos especialistas no assunto, deixando de lado alguns itens (como genericidade sobre tipos primitivos, tornando possível fazer declarações do tipo ArrayList), e a JSR-121 (Isolates) foi postergada para o J2SE 6.0 (ou 5.1, se tivermos sorte). O motivo é sempre o mesmo. Não dificultar demais a transição; não exigir mudanças de APIs sem compatibilidade retroativa; e, o que é igualmente importante, não exigir mudanças profundas na JVM, que impliquem que o HotSpot da Sun e JVMs de outros fornecedores levem muito tempo para “estabilizar” – ou seja, implementar a nova especificação de forma robusta, eficiente, pronta para aplicações de missão crítica.
Estes sacrifícios foram necessários porque, no grande plano das coisas, os primeiros builds do J2SE 5.0 precisam ser tão robustos quanto possível. Muito mais que o tradicional para versões “ponto-zero”. E as primeiras JVMs 5.0 de parceiros importantes da Sun, como BEA e IBM, também não podem demorar muito para sair. Caso contrário, toda uma montanha de novas tecnologias amarradas ao J2SE 5.0 também terá sua adoção atrasada.
As anotações são uma funcionalidade chave para todas essas novas tecnologias.
Alô, Mundo
No momento em que escrevo, já temos drafts públicos de pelo menos duas novas especificações importantes que tiram proveito de anotações: JAX-RPC 2.0 (JSR-224) e EJB 3.0 (JSR-220). Quando este artigo chegar a suas mãos, outra API, a JSR-245 (JSP 2.1) estará em revisão interna (acessível somente a membros do JCP). Estas e outras APIs “pioneiras” de anotações estarão prontas até o final deste ano, pois janeiro de 2005 é a data do draft final do J2EE 1.5, que integra tais APIs. Embora a versão final da especificação J2EE 1.5 e de suas primeiras implementações ainda vá demorar outro meio ano, a maioria dessas APIs componentes estará pronta para uso de forma independente, exigindo etapas adicionais para a instalação em containers J2EE 1.4, ou mesmo usando apenas o J2SE 5.0.
As seguintes são as JSRs (no momento de escrita) que suportam anotações:
• 175 – Especificação de Anotações
• 181 – Web Services
• 220 – EJB 3.0
• 221 – JDBC 4.0
• 224 – JAX-RPC 2.0
• 245 – JSP 2.1
• 250 – Anotações comuns para J2SE e J2EE
Nada melhor que usar uma dessas APIs, em vez de exemplos artificiais, para seduzi-lo(a) com o poder das anotações. E já que EJB tem fama de complicado, por que não começar por ele?
@Stateless public class AloBean {
public String alo (String nome) {
return “Alo, “ + nome;
}
}
Confesse: você já viu o “Alô Mundo” implementado uma dúzia de vezes só em livros de EJB, mas nenhuma vez com tão pouco código. Vamos enumerar tudo o que não foi necessário:
• Criar a interface do bean (estendendo EJBObject) e a interface Home
• Definir métodos de interfaces EJB, como ejbCreate() etc.
• Criar descritores e fazer a geração de stubs
• Declarar exceções impostas pelo padrão EJB, como RemoteException ou EJBException
Se o exemplo fosse mais completo, com cliente, EJBs stateful, CMP e outros, economizaríamos ainda mais trabalho. Por exemplo, não seria preciso nenhum código de lookup complicado usando JNDI, homes, chamadas a narrow() etc.
Boa parte dessas simplificações deve-se diretamente ao uso de anotações. Por exemplo, é fácil ver como a anotação @Stateless “marca” a classe como um session bean stateless. Isso substitui a necessidade de se implementar ou herdar algum tipo da API de EJB. Mas até nos casos das melhorias que não são diretamente substituídas por anotações (por exemplo, dispensar a implementação de interfaces como EJBObject), pode-se dizer que as anotações viabilizam essas melhorias de forma indireta (veja o quadro “Anotações como paradigma”).
Consumindo anotações
A maioria dos programadores deverá apenas “consumir” anotações, ou seja, declarar anotações que foram definidas por alguma API ou biblioteca de terceiros. A sintaxe da declaração de anotações é simples e são poucas as regras de uso. Essas regras são definidas (adivinhe) por anotações; no caso, pelas “meta-anotações”, que são declaradas no pacote java.lang.annotation:
• @Target – vários tipos de declarações podem receber anotações, mas cada anotação pode restringir as declarações para as quais é válida. Essas restrições são definidas por @Target, cujos valores permitidos (ElementType) são: TYPE (classe/interface/enum), METHOD, CONSTRUCTOR, FIELD, PARAMETER, LOCAL_VARIABLE, PACKAGE e ANNOTATION_TYPE (para meta-anotações).
• @Retention – determina o grau de “persistência” da anotação, um dos valores do enum RetentionPolicy: SOURCE (indicando que a anotação só existe no código-fonte); CLASS (a anotação é preservada nos arquivos .class); e RUNTIME (a anotação também é disponível via reflection).
• @Documented – determina que uma anotação seja considerada pelo javadoc como parte da API pública dos tipos anotados, sendo incluídas na documentação gerada.
• @Inherited ...