Seções iMasters
Desenvolvimento

Analisando profundamente o Spring Roo

Texto original de Milton
Keynes, disponível em http://alblue.bandlem.com/2010/11/delving-into-spring-roo.html

?

Eu
tive que trabalhar com JPA recentemente, e pensei em aproveitar a oportunidade para
descobrir mais sobre o Spring Roo. A primeira vez
que eu ouvi falar dele foi no QCon Londres 2010, e na época eu me
lembro de pensar quão fácil era construir um aplicativo a partir de componentes
simples.

Uma
das coisas que também me encorajaram foi que o aplicativo gerado também era um
pacote OSGi válido; ótimo. Então quando o Roo 1.1 foi lançado, eu
dei uma olhada nele. (Infelizmente, e de certa forma ironicamente, enquanto o Roo 1.1 estava sendo executado
em um contêiner OSGi, os produtos gerados não eram mais pacotes do OSGi. O. Roo-1052
tem mais informação sobre esse deslize).

Antes
de falar sobre como usar o Spring Roo, vale a pena mencionar o que ele faz e
por quê. O objetivo do Roo é facilitar a construção de aplicativos web que têm entidades persistentes; em outras palavras, seu tipo de setup
web/servlet/jsp/hibernate típico. No entanto, a maneira como ele chega ao seu
objetivo é de certa maneira diferente das outras ferramentas. Em vez de
modificar o código-fonte que você escreve, ele cria arquivos adicionais que ele
mesmo gera. Ele então usa – efetivamente – um #include em tempo de compilação
para trazer aqueles fragmentos para dentro da sua classe. Isso é feito com o
compilador AspectJ e, de um modo único e razoavelmente justo, ele usa o AspectJ
como algo a mais do que apenas envolver um método com demonstrações de log.

O resultado final é que você escreve um conjunto mínimo de
códigos em sua classe, e o Roo automaticamente gera os fragmentos necessários
do  AspectJ para suportar o que você
escreveu (aqueles que viram o Project Lombok já devem ter visto esse tipo de abordagem em um
IDE.)

Usar
o Spring Roo é bastante fácil. Existe um roo.sh executável (roo.exe no Windows) que
traz um prompt roo>, no qual você pode
acessar uma variedade de comandos. Diferentemente de uma shell OSGi padrão,
existe a conclusão de TAB; outro bônus é o fato de que os comandos que não
estão ativos ficam escondidos da lista. Finalmente, existe um sistema de hint
no qual você pode usar um chamado (com hint) para trazer uma lista do que você
pode fazer.

Os
passos são os seguintes:

  • Crie um projeto
  • Configure o mecanismo de persistência
    (database, mapping provider)
  • Crie uma (ou mais) entidades
  • (Opcional) Crie um contêiner web

Projeto

Criar
um projeto é bastante fácil – você precisa executar project –topLevelPackage com.example.
Ele gera um número de diretórios fontes, uma pasta spring e um arquivo de
propriedades log4j, juntamente com um projeto Maven para construir todos eles.

 roo> project --topLevelPackage com.example
Created /tmp/example/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Created SRC_MAIN_RESOURCES/log4j.properties

Persistência

Configurar
a persistência também é fácil. O persistence setup –provider p
–database db
fará todo o trabalho duro para você em termos de configurar o arquivo persistence.xml, os drivers de classes para usar e
as configurações por provedor que você precisa saber. Provedores como

EclipseLink, OpenJPA e Hibernate estão disponíveis, bem como os drivers de
banco de dados como DB2, Derby, Oracle, e assim por diante. (O setup entende que
se você utilizar um driver comercial, você terá que instalá-lo manualmente no
seu repositório Maven para que ele seja encontrado). Use a chave TAB para ter
uma lista, ou complete o que você está digitando, fazendo isto:

 com.example roo> persistence setup --provider ECLIPSELINK  --database DERBY 
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Managed ROOT/pom.xml [Added dependency org.apache.derby:derby:10.6.1.0]
Managed ROOT/pom.xml [Added dependency org.eclipse.persistence:eclipselink:2.1.0]
Managed ROOT/pom.xml [Added dependency org.eclipse.persistence:javax.persistence:2.0.1]
Managed ROOT/pom.xml [Added dependency org.hibernate:hibernate-validator:4.1.0.Final]
Managed ROOT/pom.xml [Added dependency javax.validation:validation-api:1.0.0.GA]
Managed ROOT/pom.xml [Added dependency cglib:cglib-nodep:2.2]
Managed ROOT/pom.xml [Added dependency javax.transaction:jta:1.1]
Managed ROOT/pom.xml [Added dependency org.springframework:spring-jdbc:${spring.version}]
Managed ROOT/pom.xml [Added dependency org.springframework:spring-orm:${spring.version}]
Managed ROOT/pom.xml [Added dependency commons-pool:commons-pool:1.5.4]
Managed ROOT/pom.xml [Added dependency commons-dbcp:commons-dbcp:1.3]
Managed ROOT/pom.xml

Entidades

Agora
somos capazes de criar entidades. O entity –class c inicia todo o processo de geração de
entidades; você pode digitar em um nome completo qualificado ou usar ~ para
representar o pacote do projeto.

com.example roo> entity --class ~.Employee 
Created SRC_MAIN_JAVA/com/example
Created SRC_MAIN_JAVA/com/example/Employee.java
Created SRC_MAIN_JAVA/com/example/Employee_Roo_Configurable.aj
Created SRC_MAIN_JAVA/com/example/Employee_Roo_Entity.aj
Created SRC_MAIN_JAVA/com/example/Employee_Roo_ToString.aj

Neste
ponto, temos um projeto capaz de ser usado como um puro provedor JPA. Antes de
seguirmos em frente, vale a pena dar uma olhada no que foi gerado:

  • pom.xml -
    os detalhes do projeto, diretórios fonte, e assim por diante
  • persistence.xml - define o banco de dados, a configuração dos mappings e
    assim por diante
  • *.properties -
    para o fornecimento de dados mutáveis, como identidade do usuário, senha e níveis de logging 
  • *.aj -
    os fragmentos do aspecto
  • Employee.java
    - um único arquivo Java

O
Employee é bastante simples: até agora, não adicionamos nada a ele. Na verdade,
além de algumas anotações (@RooJavaBean, @RooToString, @RooEntity), ele não tem nenhum conteúdo. Podemos
adicionar um field usando o console para dar um name e um manager ao employee.

~.Employee roo> field string --fieldName name 
Managed SRC_MAIN_JAVA/com/example/Employee.java
Created SRC_MAIN_JAVA/com/example/Employee_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/com/example/Employee_Roo_ToString.aj
~.Employee roo> field reference --fieldName manager --type ~.Employee
Managed SRC_MAIN_JAVA/com/example/Employee.java
Managed SRC_MAIN_JAVA/com/example/Employee_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/com/example/Employee_Roo_ToString.aj

Tudo
que fizemos foi adicionar alguns campos à classe, uma deles com uma única
anotação JPA:

@RooJavaBean
@RooToString
@RooEntity
public class Employee {
private String name;
@ManyToOne
private Employee manager;
}

A
parte interessante é aquela que você não vê, que está sendo gerada nos arquivos
*.aj. Por exemplo, dê uma
olhada no arquivo Employee_Roo_ToString.aj
:

privileged aspect Employee_Roo_ToString {
public String Employee.toString() {
StringBuilder sb = new StringBuilder();
sb.append("Id: ").append(getId()).append(", ");
sb.append("Version: ").append(getVersion()).append(", ");
sb.append("Name: ").append(getName()).append(", ");
sb.append("Manager: ").append(getManager());
return sb.toString();
}
}

Este
aspecto, quando compilado com o AspectJ, efetivamente insere uma toString() dentro da sua classe, automaticamente.
Ele usa o name e o manager que acabamos de adicionar; e, na verdade, se você fosse
até o arquivo Employee.java e o editasse com seu editor de texto preferido,
quando você fosse salvá-lo, o Roo notaria e faria a atualização do toString()
automaticamente.

O id e e a versão são definidos no arquivo
Employee_Roo_Entity.aj, então as entidades Roo as têm. Os IDs são representados
por um Long por padrão (apesar de que você pode mudar isso quando a entidade é
criada), bem como por uma versão do Integer (para suportar a verificação da recência
quando duas atualizações ocorrem na mesma linha do banco de dados).

Finalmente, também temos o
Employee_Roo_JavaBean.aj, que
gera os métodos getName() e o setName() baseados nos campos que você adiciona.
Claro que a maioria dos IDEs podem fazer isso por você, mas o Roo o tira do seu
IDE e o coloca em um processo de monitoramento autônomo que pode atualizar os
aspectos automaticamente.

Se você tiver necessidade de fazer uma implementação
específica – digamos, para pré-validar um campo – então você pode simplesmente
escrever o setName() no seu arquivo
Employee.java. O Roo percebe que ele já está lá e
não se incomoda em gerá-lo novamente.

Existe
o controller web também, apesar de que não vou falar sobre ele aqui. Ao
executar controller all, ele irá gerar
uma grande quantidade de código para você, e o perform command –mavenCommand
jetty:run irá desenvolver sozinho o ambiente

Jetty para testá-lo.

Por
ser “scriptável”, você pode facilmente repetir isso ao copiar e colar o código
abaixo em um prompt shell do Roo:

project --topLevelPackage com.example
persistence setup --provider ECLIPSELINK --database DERBY
entity --class ~.Employee
field string --fieldName name
field reference --fieldName manager --type Employee
controller all --package ~.web
perform command --mavenCommand jetty:run

Depois
de ter feito isso, aponte seu browser para http://localhost:8080/example/ e veja o aplicativo em ação.

Do que não gostar?

Configuração
simples de projetos, integração com uma variedade de provedores e bancos de
dados, entradas de comandos únicas – o que poderia ser melhor?

Bem,
apesar de ser uma excelente ideia em teoria, ele tem suas inconveniências. Uma
delas é que apesar de usar aspectos dessa maneira ser uma ótima ideia,
ainda existe uma preocupação com a utilização de aspectos que pode irritar
algumas pessoas. A segunda é que às vezes não fica claro o que está acontecendo
nos bastidores, o que demora um pouco para se acostumar.

É
realmente uma pena o Roo ter parado de gerar pacotes OSGi por padrão.
Parcialmente, a
autonomia das especificações da empresa não está lá ainda, então gerar um header Meta-Persistence pode não ser imediatamente
possível; mas as maiores reclamações contra o Roo eram de que ele estava usando
o
SpringSource EBR em vez do Maven central. Apesar de o
EBR ter sido ótimo para popularizar o OSGi, muitos projetos upstream estão
migrando para usar os metadados do OSGi, então não é imediatamente claro se
isso é de fato um problema hoje como era quando o Roo foi lançado.

A
licença também é um ponto potencial de problema. Apesar de as anotações do Roo
serem licenciadas sob a licença Apache, o Roo (que lê e gera arquivos *.aj) é GPL. Alguns se preocupam que isso possa
introduzir dependências virais no GPL –
seja por algum tipo de
ligação direta, ou seja uma grande preocupação gerada
automaticamente, o Roo difere dependendo de para quem você pergunta. De
qualquer maneira, é algo a se considerar quando se baseia um aplicativo no Roo.

Conclusão

O
Spring Roo é um ótimo ambiente para criar entidades persistentes e aplicativos
web para os executar. Obviamente nem todos aplicativos se encaixam neste molde,
então ele tem uma audiência limitada. Sendo um projeto Spring, ele usará fortemente o Spring
para a geração das entidades de execução; mais do que você precisa para gerar
um pacote OSGi JPA. É também um ótimo aplicativo de programação orientado para
aspectos, que mais do que os exemplos “log-it-and-see” que você encontra por aí.

No
entanto, as preocupações sobre a licença e o fato de ele não gerar mais pacotes
OSGi significam que ele é indicado para criação de protótipos ou para aprender
como gerar entidades JPA. Apesar de tudo, a abordagem é promissora e com uma
licença ou um estilo diferente de geração ele poderia ser um vencedor.

Mensagem do anunciante:

Torne-se um Parceiro de Software Intel®. Filie-se ao Intel® Developer Zone. Intel®Developer Zone

Qual a sua opinião?