Desenvolvimento

19 nov, 2012

Apresentando o Spring Roo – Parte 05: grave complementos avançados e de Wrapper do Spring Roo

Publicidade

A parte 3 desta série, “Apresentando o Spring Roo”, discute a arquitetura de complementos do Spring Roo e como criar internacionalização e complementos simples usando o comando criar complemento. Este artigo foca os dois tipos restantes de complementos suportados pelo Spring Roo, isto é, complemento avançado e de wrapper. Recomenda-se que a Parte 3 seja consultada antes de continuar.

Introdução ao complemento avançado

O complemento avançado permite que o Spring Roo faça tudo que um complemento simples pode fazer, como atualizar um arquivo Maven POM com dependências ou plug-ins, atualizar ou incluir arquivos de configuração, além de aprimorar tipos Java existentes e introduzir novos tipos Java usando AspectJ ITDs. A capacidade de incluir um código fonte torna os complementos avançados muito eficientes em comparação a todos os demais complementos. Antes de criar um complemento avançado do Spring Roo, considere um complemento avançado existente fornecido pelo Spring Roo.

Complemento avançado em ação

Um complemento avançado é o JPA, que executa trabalho relacionado à persistência, isto é, incluindo suporte para bancos de dados e criando novas entidades. Para visualizar isso em ação, abra o shell Roo e execute os comandos em Lista 1. Neste artigo, o Spring Roo versão 1.2.0.M1 é utilizado.

project --topLevelPackage com.dw.demo --projectName entity-demo 
jpa setup --database FIREBIRD --provider HIBERNATE 
entity --class ~.domain.Book

Ambos os comandos configuração de jpa e entidade correspondem a um complemento avançado chamado org.springframework.roo.addon.jpa. A saída dos comandos configuração de jpa e entidade no shell Roo possibilita uma clara distinção entre complementos simples e avançados. Lista 2 mostra a saída do comando configuração de JPA.

Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties 
Updated ROOT/pom.xml [added dependencies ...] 
Updated SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml 
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml

A saída do comando configuração de jpa mostra que ele está executando funções de configuração, como a inclusão de dependências em pom.xml, atualizando o applicationContext.xml do Spring e criando o persistence.xml específico à persistência. Presume-se que o comando de configuração de JPA corresponda a um complemento simples, porque não está criando ou atualizando o código fonte Java. Use um complemento simples para cenários semelhantes à configuração mostrada acima.

Lista 3 mostra a saída do comando entidade especificado.

Created SRC_MAIN_JAVA/com/dw/demo/domain 
Created SRC_MAIN_JAVA/com/dw/demo/domain/Book.java 
Created SRC_MAIN_JAVA/com/dw/demo/domain/Book_Roo_Configurable.aj 
Created SRC_MAIN_JAVA/com/dw/demo/domain/Book_Roo_Jpa_Entity.aj 
Created SRC_MAIN_JAVA/com/dw/demo/domain/Book_Roo_Entity.aj 
Created SRC_MAIN_JAVA/com/dw/demo/domain/Book_Roo_ToString.aj

A saída mostra a criação de um arquivo Java chamado Book.java e quatro arquivos *.aj. A regra final para identificar um complemento avançado é a geração de arquivos Java ou *.aj, ou ambos, como no caso do comando de entidade. Esses *Roo_*.aj são chamados de Inter-type Declarations (ou ITDs). As ITDs permitem um tipo (um aspecto) para fazer declarações para outro tipo, isto é, é possível modificar a estrutura estática de qualquer tipo incluindo métodos, campos ou alterando sua hierarquia de tipo. O Roo usa uma ITD como um artefato de geração de códigos e os gerencia durante todo o seu tempo de vida. As ITDs permitem que o Roo gere um código em uma unidade de compilação separada, mas elas são combinados na mesma classe compilada.

Após visualizar a saída do comando entidade, considere como esses artefatos (arquivos .java e.aj) são gerados pelo Spring Roo. Consultea  Lista 4 para obter uma amostra de um arquivo Book.java.

package com.dw.demo.domain; 

import org.springframework.roo.addon.entity.RooEntity; 
import org.springframework.roo.addon.javabean.RooJavaBean; 
import org.springframework.roo.addon.tostring.RooToString; 

@RooJavaBean 
@RooToString 
@RooEntity 
public class Book { 
}

O arquivo Java parece normal, exceto para anotações na classe. Observando os nomes da anotação e os arquivos .aj, nota-se que algumas dessas anotações correspondem à funcionalidade incluída por arquivos .aj. Por exemplo: RooToString corresponde ao arquivo Book_Roo_ToString.aj e ao método incluir toString(). RooEntity corresponde a Book_Roo_Entity .aj, Book_Roo_Jpa_Entity e métodos relacionados à persistência. Deixemos o resto de lado por ora. Para entender como essas anotações levam à geração de ITDs, explore como o Spring Roo fornece funcionalidades de complemento avançado.

  1. Na inicialização de shell Roo, ele varrerá todas as classes e registrará todas as que implementam a interface CommandMarker . A interface CommandMarker informa ao Roo que essas classes definirão os comandos que esse complemento pode executar;
  2. Todos os complementos avançados registram seus serviços no tempo de execução de OSGi fornecido pelo Spring Roo. Esses serviços especificam condições nas quais ele acionará a geração de códigos. Para todos os complementos avançados, o ponto de acionamento é a presença de uma anotação. Por exemplo, um complemento avançado para a geração do método toString() é acionado somente se um tipo Java tiver a anotação RooToString. Esse é o caso com outras anotações;
  3. Mediante o uso de entity --class ~.domain.Book, o complemento criará um arquivo Java chamado Book.java com anotações. Outros complementos são acionados quando um tipo Java tem essas anotações e os arquivos .aj são gravados para eles.

Um maior esclarecimento será evidente quando criar seu próprio complemento avançado.

O complemento org.springframework.roo.addon.jpa é apenas um exemplo de complemento avançado fornecido pelo Spring Roo. Outros complementos avançados incluem: GWT, controlador, JSON e muito mais. A liberação do Spring Roo 1.2.0 contém mais dois complementos avançados:—addon-equals e addon-jsf. O addon-equals fornece implementação para métodos equivalentes e código hash para uma entidade e o addon-jsf fornece suporte a JSF em aplicativos Spring Roo. Para a reprodução da captura instantânea mais recente do Spring Roo, crie o código do Spring Roo ou faça o download da captura instantânea noturna do repositório do Spring Roo.

Inclua o método compareTo() na minha classe de entidade

Os objetos de valor ou entidades são comumente necessários para implementar a interface java.lang.Comparable e fornecer a implementação para o método compareTo() . A interface comparável impõe ordenação total sobre os objetos de cada classe que a está implementando. Quando Comparável é implementado, é possível:

  1. Chamar java.util.Collections.sort e java.util.Collections.binarySearch;
  2. Chamar java.util.Arrays.sort e java.util.Arrays.binarySearch;
  3. Usar objetos como chaves em um java.util.TreeMap;
  4. Usar objetos como elementos em um java.util.TreeSet.

Neste artigo, será criado um complemento avançado que fornecerá uma implementação de compareTo() para entidades criadas em seu aplicativo. Como deseja incluir o código Java em seu aplicativo, é preciso criar um complemento avançado.

 Configuração do Projeto

A documentação do Spring Roo explica de forma eloquente como configurar um projeto e um repositório Maven no código do Google; portanto, é desnecessário repeti-lo aqui. Observe que “spring-dw-roo-compareto-addon” será usado como o nome do projeto.

Caso não esteja usando a versão mais recente do Spring Roo, 1.2.0.RC1, faça download dela no website do projeto. Descompacte e instale essa versão conforme explicado na parte 1.

O Spring Roo descontinuou ou removeu algumas das classes usadas em versões anteriores.

Criando um complemento avançado

Após configurar o projeto, será possível visualizar um diretório chamado spring-dw-roo-compareto-addon com apenas uma pasta .svn. Na linha de comandos, acesse o diretório spring-dw-roo-compareto-addon e inicie o shell Roo. Então, digite o comando a seguir:

addon create advanced --topLevelPackage org.xebia.roo.addon.compareto --projectName spring-dw-roo-compareto-addon

Pronto! Um complemento avançado acabou de ser criado.

Em seguida, no shell Roo, dispare o comando realizar pacote para criar um complemento jar. Lista 5 mostra os arquivos gerados pelo complemento criar avançado .

Created ROOT/pom.xml 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SPRING_CONFIG_ROOT 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto/ComparetoCommands.java 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto/ComparetoOperations.java 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto/ComparetoOperationsImpl.java 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto/ComparetoMetadata.java 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto/ComparetoMetadataProvider.java 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/compareto/RooCompareto.java 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/compareto 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/compareto/configuration.xml

Alguns dos arquivos gerados, como pom.xml, readme.txt e license.txt, não precisam de introdução, pois foram apresentados na parte 3 e são autoexplicativos. Os artefatos mais interessantes são:

  • ComparetoCommands.java;
  • ComparetoOperations.java;
  • ComparetoOperationsImpl.java;
  • ComparetoMetadata.java;
  • ComparetoMetadataProvider.java;
  • RooCompareto.java.

Agora, veremos os artefatos gerados um a um.

  • ComparetoCommands.java : Esta classe implementa a interface CommandMarker e expõe dois tipos de métodos:—um com a anotação CliAvailablityIndicator e outro com a anotação CliCommand . A anotação CliAvailablityIndicator informa ao Spring Roo quando o comando deve estar visível. Por exemplo, o comando ‘entidade‘ não será disponibilizado antes de o usuário definir as configurações de persistência no shell Roo ou diretamente no projeto. Os métodos anotados com @CliCommand registram o comando com o shell Roo. A anotação @CliCommand possui dois atributos: valor, que define o nome do comando; e ajuda, que define a mensagem de ajuda exibida quando o comando de ajuda é digitado. Para obter uma explicação detalhada da classe *Commands , consulte a parte 3.
  • ComparetoOperationsImpl.java : A classe ComparetoCommands delega todo o trabalho para a classe ComparetoOperationsImpl. Os quatro métodos gerados nesta classe são:
    • isCommandAvailable(): Este método é chamado pelo método anotado com CliAvailabilityIndicator ComparetoCommands na classe ComparetoCommands para verificar se o comando deve estar visível ou não. Isso é para assegurar que os comandos estejam cientes do contexto. Este método executa várias validações. Por exemplo, se o projeto tiver sido criado, somente o comando estará visível; ou se a persistência tiver sido configurada, somente o comando deverá estar visível. Não é obrigatório ter uma condição para que o comando esteja visível. Simplesmente retorne verdade para garantir que o comando esteja sempre visível.
    • setup(): Este método é chamado pelo método setup() , na classe ComparetoCommands que é anotada com @CliCommand. O código esclarece que esta classe é responsável por executar tarefas relacionadas à configuração, como incluir dependências Maven, incluir repositórios Maven ou criar ou atualizar arquivos de contexto do Spring (como no complemento Jamon Roo na parte 3).
    • annotateType(): Este método e annotateAll() são novos métodos que não existem em complementos simples. A funcionalidade deste método é incluir uma anotação (RooCompareto) no tipo Java especificado. Este método utiliza alguns serviços fornecidos pelo Spring Roo para buscar os detalhes da Classe para o tipo Java determinado e anexar a anotação RooJCompareto a ele.
    • annotateAll(): Este método encontra todos os tipos que são anotados com a anotação RooJavaBean e chama o método annotateType() em todos esses tipos. Utilize este método quando todas as entidades forem obrigadas a ter a anotação RooCompareto .
  • RooCompareto.java: A presença desta anotação aciona o complemento para gerar o código.
  • ComparetoMetadataProvider.java: Esta classe é um serviço do Spring Roo e é chamada pelo Roo para recuperar os metadados para o complemento. Esta classe registra acionadores para incluir e remover metadados. Nenhuma mudança é necessária nesta classe, mas lembre-se que ela tem um método chamado getMetadata() que será chamado pelo Spring Roo sempre que houver qualquer tipo Java com a anotação RooCompareto .
  • ComparetoMetadata.java: Esta classe é responsável por gerar o ITD correspondente ao complemento. No código gerado, ela usa uma classe chamada ItdTypeDetailsBuilder para criar uma ITD com um campo e um método. Posteriormente neste artigo, você alterará o código padrão gerado para atender aos requisitos de incluir um método compareTo e implementar a interface Comparável.

Modificando o complemento para atender aos requisitos

Você deseja criar um complemento que deve incluir o método compareTo para classes de entidade. Será preciso:

Incluir a dependência Maven commons-lang versão 3.1 no projeto de destino. Isso é necessário, porque commons-lang fornece uma classe de construtor chamada CompareToBuilder que será usada para criar o método compareTo.

  • Faça com que a classe de entidade implemente a interface Comparável;
  • Crie uma ITD para o método compareTo.

Incluindo a dependência maven

Para atender a esses requisitos, as mudanças são necessárias nas classes ComparetoOperationsImpl e ComparetoMetadata . Faça uma mudança de cada vez.

  • Primeiro, inclua a dependência Maven commons-lang no projeto de destino. Atualize o arquivo configuration.xml para que tenha a dependência commons-lang em vez da dependência de lote do Spring fornecida padrão, como em Lista 6.
 
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<configuration>
   <dependencies>
      <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
         <version>3.1</version>
      </dependency>
   </dependencies>
</configuration>

Em seguida, modifique a implementação do método setup() na classe ComparetoOperationsImpl para ler a dependência Maven commons-lang em vez da dependência Maven de lote do Spring, como em Lista 7. O método annotateType e annotateAll() não são mostradas aqui, porque eles não apresentam mudanças.

@Component
@Service
public class ComparetoOperationsImpl implements ComparetoOperations {

@Reference
private ProjectOperations projectOperations;

@Reference
private TypeLocationService typeLocationService;

@Reference
private TypeManagementService typeManagementService;

/** {@inheritDoc} */
public void setup() {
// Install the add-on Google code repository needed to get the annotation
projectOperations.addRepository("",
new Repository("Compareto Roo add-on repository",
"Compareto Roo add-on repository",
"https://spring-dw-roo-compareto-addon.googlecode.com/svn/repo"));
List<Dependency> dependencies = new ArrayList<Dependency>();
// Install the dependency on the add-on jar (
dependencies.add(new Dependency("org.xebia.roo.addon.compareto",
"org.xebia.roo.addon.compareto", "0.1.0.BUILD-SNAPSHOT",
DependencyType.JAR, DependencyScope.PROVIDED));
Element configuration = XmlUtils.getConfiguration(getClass());
for (Element dependencyElement : XmlUtils.findElements(
"/configuration/dependencies/dependency",
configuration)) {
dependencies.add(new Dependency(dependencyElement));
}
projectOperations.addDependencies("", dependencies);
}
}

As mudanças feitas até agora são semelhantes às mudanças usadas para criar um complemento simples Jamon na parte 3.

Faça com que a classe de entidade implemente a interface comparável

Após fazer mudanças no código para incluir a dependência Maven, é necessário garantir que sua classe de entidade implemente a interface java.lang.Comparable. Para fazer isso, modifique a ITD gerada pela classe ComparetoMetadata . As classes de metadados geram a ITD usando a classe ItdTypeDetailsBuilder que fornece vários métodos de inclusão para incluir métodos, campos, anotações, interface, entre outros, em uma ITD. Para fazer com que um tipo Java implemente uma interface, use o método addImplementsType na classe ItdTypeDetailsBuilder , como na Lista 8. Somente o construtor ComparetoMetadata é exibido porque a construção da ITD ocorre nele.

public ComparetoMetadata(String identifier, JavaType aspect Name,
PhysicalTypeMetadata  governorPhysicalTypeMetadata) {
super(identifier, aspect Name, governorPhysicalTypeMetadata);
Assert.isTrue(isValid(identifier), "Metadata identification string '" +
identifier + "' does not appear to be a valid");
JavaType comparableInterface = new JavaType("java.lang.Comparable");
builder.addImplementsType(comparableInterface);
itdTypeDetails = builder.build();
}

Crie uma ITD para o método compareTo

Após fazer com que um tipo Java implemente a interface Comparável, é preciso fornecer a implementação do método compareTo. A classe CompareToBuilder fornece uma interface fluente para criar o método compareTo. O complemento equivalentes do Spring Roo usa o EqualsBuilder e o HashcodeBuilder para fornecer a implementação para os métodos equivalentes e código hash. Usaremos um exemplo para garantir que haja dúvidas sobre como o CompareToBuilder auxilia na criação do método compareTo . Suponhamos que você tenha uma entidade chamada Book e deseja fornecer a implementação compareTo para ela usando o CompareToBuilder. Lista 9 mostra a classe Book e compareTo .

import org.apache.commons.lang3.builder.CompareToBuilder;

public class Book implements Comparable {
    private String title;
    private String author;
    private double price;
    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    // getters and setters

    public int compareTo(Book o) {
	if(!(o instanceof Book)){
	  return -1;
	}
	Book book = (Book)o
        return new CompareToBuilder().append(this.title, book.title).append(this.author, 
            book.author).append(this.price, book.price).toComparison();
    }

    @Override
    public String toString() {
        return "Book [title=" + title + ", author=" + author + ", price=" + price + "]";
    }

}

O método compareTo na Lista 9 faz o seguinte:

  • Se “o” não for instanceOfBook , retorne -1;
  • Se “o” for instanceOfBook , digite cast o para Book;
  • Crie um objeto da classe CompareToBuilder e, em seguida, chame o método anexar nos campos.

Crie o método compareTo incrementalmente com estas etapas:

  • Se “o” não for instanceOf Book, retorne -1

Antes de incluir a verificação instanceOf , crie o método compareTo . Consulte Lista 10.

public ComparetoMetadata(String identifier, JavaType aspect Name, 
    PhysicalTypeMetadata governorPhysicalTypeMetadata) { 
        super(identifier, aspect Name, governorPhysicalTypeMetadata); 
        Assert.isTrue(isValid(identifier), 
            "Metadata identification string '" + identifier + 
            "' does not appear to be a valid"); 

    JavaType comparableInterface = new JavaType("java.lang.Comparable"); 
    builder.addImplementsType(comparableInterface); 
    builder.addMethod(getCompareToMethod()); 

    itdTypeDetails = builder.build(); 
} 

private MethodMetadata getCompareToMethod() { 
    final JavaType parameterType = JavaType.OBJECT; 
    final List parameterNames = 
        Arrays.asList(new JavaSymbolName("obj")); 
    final InvocableMemberBodyBuilder bodyBuilder = 
        new InvocableMemberBodyBuilder(); 
    bodyBuilder.appendFormalLine("return -1;"); 
    final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(getId(), 
        Modifier.PUBLIC, new JavaSymbolName("compareTo"), 
        JavaType.INT_PRIMITIVE, 
            AnnotatedJavaType.convertFromJavaTypes(parameterType), 
        parameterNames, bodyBuilder); 
        return methodBuilder.build(); 
}

O getCompareToMethod() gera os metadados do método compareTo usando a classe MethodMetadataBuilder . MethodMetadataBuilder é uma classe Builder fornecida pelo Spring Roo para criação de metadados de método. Para criar os metadados de método, primeiro construa um objeto MethodMetadataBuilder , passando argumentos, como modificador de acesso, nome de método, tipo de retorno, lista de parâmetros ou um construtor de corpo de método para criar os metadados para o método compareTo como na Lista 11.

private MethodMetadata getCompareToMethod() { 
        final JavaType parameterType = JavaType.OBJECT; 
        String parameterName = "obj"; 
        final List parameterNames = 
            Arrays.asList(new JavaSymbolName(parameterName)); 
        final InvocableMemberBodyBuilder bodyBuilder = 
            new InvocableMemberBodyBuilder(); 
        final String typeName = destination.getSimpleTypeName(); 
        bodyBuilder.appendFormalLine("if (!(" + parameterName + 
            " instanceof " + typeName + ")) {"); 
        bodyBuilder.indent(); 
        bodyBuilder.appendFormalLine("return -1;"); 
        bodyBuilder.indentRemove(); 
        bodyBuilder.appendFormalLine("}"); 

        bodyBuilder.appendFormalLine("return -1;"); 
        final MethodMetadataBuilder methodBuilder = 
            new MethodMetadataBuilder(getId(), 
            Modifier.PUBLIC, new JavaSymbolName("compareTo"), 
            JavaType.INT_PRIMITIVE, 
            AnnotatedJavaType.convertFromJavaTypes(parameterType), 
            parameterNames, bodyBuilder); 
        return methodBuilder.build(); 
    }
  • Se “o” for instanceOfBook, digite cast o para Book

A próxima etapa é um cast, portanto, é possível criar o método compareTo . Para fazer isso, anexe esta linha após a verificação instanceOf:

bodyBuilder.appendFormalLine(typeName + " rhs = (" + typeName + ") " + 
    OBJECT_NAME + ";");
  • Crie o objeto da classe CompareToBuilder e, em seguida, chame o método anexar nos campos

Para criar o método compareTo , é necessário acesso a todos os campos de uma classe. A classe ComparetoMetadata não contém nenhuma informação sobre o tipo, portanto, não é possível obter campos da classe. Essas informações podem ser fornecidas pelo ComparetoMetadataProvider como na Lista 12.

protected ItdTypeDetailsProvidingMetadataItem getMetadata(String metadataId,
    JavaType aspect Name, PhysicalTypeMetadata governorPhysicalTypeMetadata, 
    String itdFilename) { 

        final String[] excludeFields = {};

        final MemberDetails memberDetails = 
            getMemberDetails(governorPhysicalTypeMetadata); 
        if (memberDetails == null) { 
            return null; 
        } 

        final JavaType javaType = 
            governorPhysicalTypeMetadata.getMemberHoldingTypeDetails().getName();

        final List compareToFields = 
            locateFields(javaType, excludeFields, memberDetails, metadataId); 

        return new ComparetoMetadata(metadataId, aspect Name,
        governorPhysicalTypeMetadata, compareToFields);
    } 

private List locateFields(final JavaType javaType, final String[]
        excludeFields, final MemberDetails memberDetails, final String
        metadataIdentificationString) { 

	final SortedSet locatedFields = new TreeSet(new
    	  Comparator() { 
            public int compare(final FieldMetadata l, final FieldMetadata r) { 
                return l.getFieldName().compareTo(r.getFieldName()); 
            } 
        }); 

        final List excludeFieldsList = 
            CollectionUtils.arrayToList(excludeFields); 
        final FieldMetadata versionField = 
            persistenceMemberLocator.getVersionField(javaType); 

        for (final FieldMetadata field : memberDetails.getFields()) { 
            if (excludeFieldsList.contains(field.getFieldName().getSymbolName())) { 
                continue; 
            } 
            if (Modifier.isStatic(field.getModifier()) ||
        Modifier.isTransient(field.getModifier()) ||
      		field.getFieldType().isCommonCollectionType() 
                    || field.getFieldType().isArray()) { 
                continue; 
            } 
            if (versionField != null && 
                field.getFieldName().equals(versionField.getFieldName())) { 
                    continue; 
                } 

            locatedFields.add(field); 

            metadataDependencyRegistry.registerDependency(
                field.getDeclaredByMetadataId(), 
                metadataIdentificationString
            ); 
        } 

        return new ArrayList(locatedFields); 
    }

Quando tiver os campos, passe-os para ComparetoMetadata a fim de que possa criar o método compareTo , como mostra a Lista 13.

private List compareToFields; 

public ComparetoMetadata(String identifier, JavaType aspectName, 
    PhysicalTypeMetadata governorPhysicalTypeMetadata, 
    List compareToFields) { 

        super(identifier, aspectName, governorPhysicalTypeMetadata); 
        Assert.isTrue(isValid(identifier), 
            "Metadata identification string '" + identifier + 
                "' does not appear to be a valid"); 

        this.compareToFields = compareToFields; 
        if (!CollectionUtils.isEmpty(compareToFields)) { 
            JavaType comparableInterface = new JavaType("java.lang.Comparable"); 
            builder.addImplementsType(comparableInterface); 
            builder.addMethod(getCompareToMethod()); 
        } 
        itdTypeDetails = builder.build(); 

    } 

    private MethodMetadata getCompareToMethod() { 
        final JavaType parameterType = JavaType.OBJECT; 
        String parameterName = "obj"; 
        final List parameterNames = 
            Arrays.asList(new JavaSymbolName(parameterName)); 
        final InvocableMemberBodyBuilder bodyBuilder = 
            new InvocableMemberBodyBuilder();
        final ImportRegistrationResolver imports = 
            builder.getImportRegistrationResolver(); 
            imports.addImport(
                newJavaType("org.apache.commons.lang3.builder.CompareToBuilder")
            );

        final String typeName = destination.getSimpleTypeName(); 
        bodyBuilder.appendFormalLine("if (!(" + parameterName + " instanceof " + 
            typeName + ")) {"); 
        bodyBuilder.indent(); 
        bodyBuilder.appendFormalLine("return -1;"); 
        bodyBuilder.indentRemove(); 
        bodyBuilder.appendFormalLine("}"); 

        bodyBuilder.appendFormalLine(typeName + " rhs = (" + typeName + ") " + 
            parameterName + ";"); 
        final StringBuilder builder = new StringBuilder(); 
        builder.append("return new CompareToBuilder()"); 

        for (final FieldMetadata field : compareToFields) { 
            builder.append(".append(" + field.getFieldName() + ", rhs." + 
                field.getFieldName() + ")"); 
        } 
        builder.append(".toComparison();"); 

        bodyBuilder.appendFormalLine(builder.toString()); 

        final MethodMetadataBuilder methodBuilder = 
                new MethodMetadataBuilder(getId(), 
                    Modifier.PUBLIC, new JavaSymbolName("compareTo"), 
                    JavaType.INT_PRIMITIVE, 
                    AnnotatedJavaType.convertFromJavaTypes(parameterType), 
                    parameterNames, bodyBuilder); 
        return methodBuilder.build(); 
    }

Teste

Isso conclui a implementação do complemento compareTo . É possível fazer download do código de origem completo deste complemento a partir do repositório de código do Google. Agora, é possível testar o compareTo que acabou de ser criado.

  • Saia do shell roo e execute o comando instalação limpa do mvn . Durante o processo de construção, será solicitada a passphrase GPG;
  • Após o complemento do Roo ser criado, abra uma nova linha de comandos e crie um diretório chamado livraria;
  • Acesse o diretório livraria e digite o comando roo para abrir um shell Roo;
  • Execute os comandos de Lista 14 no shell Roo.
project --topLevelPackage com.xebia.roo.bookshop --projectName bookshop  
jpa setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE  
entity jpa --class ~.domain.Book  
field string --fieldName title --notNull  
field string --fieldName author --notNull  
field number --fieldName price --type double --notNull
  • Para instalar e iniciar o complemento, digite o que segue no shell Roo:
osgi start --url file://<location to compareTo addon jar>

Isso deverá instalar e ativar seu complemento compareTo. É possível visualizar o status do complemento usando o comando OSGi ps.

  • Digitecompareto e pressione tab para visualizar os três comandos do complemento compareto na Lista 15.
roo> compareto

compareto add      compareto all      compareto setup
  • As etapas configuradas na Lista 15 confirmará se o complemento compareto está adequadamente instalado. A próxima etapa é executar o comando configuração, que configurará as dependências necessárias. Consulte Lista 16.
roo> compareto setup 

Updated ROOT/pom.xml [added repository 
    https://spring-dw-roo-compareto-addon.googlecode.com/svn/repo; 
    added dependencies org.xebia.roo.addon.compareto:org.xebia.roo.addon.compareto:
        0.1.0.BUILD,
    org.apache.commons:commons-lang3:3.1;
    removed dependency org.apache.commons:commons-lang3:3.0.1]
  • Quando executar o comando compareto setup a próxima etapa lógica é incluir o método compareTo em classes de entidade. Isso pode ser feito por meio de compareto add ou compareto all, dependendo se deseja gerar o método compareTo para somente uma classe de entidade ou todas as classes de entidade. Incluiremos o método compareTo em todas as classes de entidade na amostra do aplicativo bookshop (consulte Downloads). Consulte Lista 17.
roo> compareto all 
Updated SRC_MAIN_JAVA/com/xebia/roo/bookshop/domain/Book.java 
Created SRC_MAIN_JAVA/com/xebia/roo/bookshop/domain/Book_Roo_Compareto.aj

Como pode ver acima, na saída do comando compareto all, um ITD chamado Book_Roo_Compareto.aj é gerado. Esse arquivo conterá o método compareTo. A Lista 18 mostra o Book_Roo_Compareto.aj.

import org.apache.commons.lang.builder.CompareToBuilder; 

privileged aspect Book_Roo_Compareto { 

    declare parents: Book implements java.lang.Comparable; 

    public int Book.compareTo(java.lang.Object obj) { 
        if (!(obj instanceof Book)) { 
            return -1; 
        } 
        Book rhs = (Book) obj; 
        return new CompareToBuilder().append(author, 
            rhs.author).append(id, rhs.id).append(price, rhs.price).append(title, 
            rhs.title).toComparison(); 
    } 

}
  • Execute o comandorealizar pacote no shell Roo para verificar se tudo está compilado corretamente após incluir o complemento. Para sua surpresa, a construção falhará porque o Maven não consegue resolver dependências do pacote configurável do Sprin Roo. Essas dependências de pacote configurável vêm do complemento compareTo . É necessária a dependência do complemento, porque suas entidades têm de ser anotadas com a anotação Compareto. Essa é a única coisa que precisa do complemento. A melhor forma encontrada é criar outro módulo Maven e ter todas as dependências do complemento lá. É semelhante com o que o Sprin Roo faz. O Spring Roo não cria dependência com cada complemento usado. Ele possui anotações jar de Spring Roo comuns que contêm todas as dependências. O xebia-spring-roo-addon-annotation do projeto foi criado e a anotação Compareto foi inserida neste módulo. Em seguida, o configuration.xml foi atualizado para incluir esse jar no projeto do cliente, em vez do jar do complemento. A Lista 19 mostra o configuration.xml.
 <?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<configuration> 
  <dependencies> 
    <dependency> 
      <groupId>org.apache.commons</groupId> 
      <artifactId>commons-lang3</artifactId> 
      <version>3.1</version> 
    </dependency> 
    <dependency> 
      <groupId>org.xebia.roo.addon</groupId> 
      <artifactId>xebia-spring-roo-addon-annotations</artifactId> 
      <version>0.0.1</version> 
    </dependency> 
  </dependencies> 

  <repositories> 
    <repository> 
      <id>spring-roo-addon-annoations</id> 
      <name>Spring Roo Addon Annotation</name> 
      <url>https://xebia-spring-roo-addon-annotations.googlecode.com/svn/repo</url> 
    </repository> 
  </repositories>  
</configuration>

Atualize a classe ComparetoOperationsImpl do método setup() para ler as novas dependências e repositórios especificados no arquivo configuration.xml atualizado. Consulte Lista 20.

public void setup() { bu

List<Dependency> dependencies = new ArrayList<Dependency>();

Element configuration = XmlUtils.getConfiguration(getClass());
for (Element dependencyElement :
XmlUtils.findElements("/configuration/dependencies/dependency",
configuration)) {

dependencies.add(new Dependency(dependencyElement));

}

projectOperations.addDependencies("", dependencies);

List<Element> repositories = XmlUtils.findElements(
"/configuration/repositories/repository", configuration);
for (Element repositoryElement : repositories) {
Repository repository = new Repository(repositoryElement);
projectOperations.addRepository(projectOperations.getFocusedModuleName(),
repository);
}
}

Em seguida, siga estas etapas:

  • Crie o complemento novamente executando instalação limpa do mvn.
  • Gere novamente o cliente como na etapa 4.
  • Para remover o complemento antigo, digite este comando no shell Roo:
addon remove --bundleSymbolicName
org.xebia.roo.addon.compareto
  • Instale o complemento novamente executando o comando osgi install;
  • Quando o complemento for instalado, execute os comandos compareto setup e compareto all;
    As ITDs compareTo poderão ser visualizadas. Execute o comando realizar pacote e tudo funcionará direito.

Quando testar que seu complemento está funcionando em seu ambiente de desenvolvimento, será possível realizar seu push para o projeto do código do Google criado. Para publicar o complemento para o mundo, siga o mesmo procedimento usado para publicar o complemento i18n na parte 3. Da mesma forma, para registrar o complemento com o RooBot, siga a documentação do Spring Roo.

Torne os drivers JDBC não OSGi compatíveis com OSGi com o complemento de wrapper

Um caso de uso comum do complemento de wrapper é para a conversão de drivers JDBC não OSGi para pacotes configuráveis compatíveis com OSGi. Um local em que é necessário quebrar um driver JDBC é quando você tem de realizar engenharia reversa em um banco de dados Oracle usando o Roo. O Spring Roo não fornece drivers JDBC Oracle OSGi, devido a problemas de copyright. Antes de fazer a engenharia reversa de um banco de dados Oracle, primeiro torne o driver compatível com OSGi. Para criar um complemento de wrapper para um driver JDBC Oracle:

  • Instale o jar JDBC Oracle em seu repositório Maven da máquina local digitando este comando
mvn install:install-file -Dfile=ojdbc5.jar -DgroupId=com.oracle 
  -DartifactId=ojdbc5 -Dversion=11.2.0.2 -Dpackaging=jar
  • Crie um novo diretório chamado oracle-wrapper-addon e, a partir da linha de comandos, acesse o diretório.
  • Abra o shell Roo e execute o comando de complemento de wrapper: addon create wrapper --topLevelPackage com.oracle.wrapper.jdbc --groupId com.oracle --artifactId ojdbc5 --version 11.2.0.2 --vendorName Oracle --licenseUrl oracle.com Esse comando gerará somente arquivos pom.xml que serão usados para converter um driver JDBC Oracle não OSGi em um driver OSGi
  • De dentro do shell Roo, excute este comando para criar o pacote configurável do OSGi: perform command --mavenCommand bundle:bundle

Pronto. Um pacote configurável de OSGi foi criado com sucesso a partir de um jar não OSGi.

Conclusão

Neste artigo, você aprendeu sobre o complemento avançado e de wrapper no Spring Roo. Também aprendeu a criar complementos avançados e de wrapper. Isso conclui sua exploração em um recurso muito importante do Spring Roo: gravação de complementos. Sempre que desejar estender a funcionalidade do Spring Roo, lembre-se de pensar sobre a criação de complementos.

Na próxima parte desta série, “Apresentando o Spring Roo”, será discutido como gravar aplicativos GWT usando o Spring Roo.

Downloads

Descrição Nome Tamanho Método de download
Sample code bookshop.zip 14KB HTTP
Sample code spring-dw-roo-compareto-addon.zip 18KB HTTP

Informações sobre métodos de download

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Conecte-se com outros usuários do developerWorks enquanto explora os blogs, fóruns, grupos e wikis voltados para desenvolvedores. Ajude a desenvolver o software livre do mundo real na comunidade do developerWorks.

***

Sobre o autor: Shekhar Gulati é consultor Java na Xebia Índia. Ele tem seis anos de experiência corporativa em Java. Possui ampla experiência em projetos do portfólio Spring, como Spring, Spring-WS e Spring Roo. Seus interesses são Spring, bancos de dados NoSQL, Hadoop, estruturas RAD, como Spring Roo, computação em nuvem (principalmente, serviços PaaS, como Google App Engine, CloudFoundry, OpenShift), Hadoop. Escreve constantemente para JavaLobby, Developer.com, IBM developerWorks e seu próprio blog em http://whyjava.wordpress.com/. Você pode segui-lo no Twitter @ http://twitter.com/#!/shekhargulati.

***

Artigo original disponível em: http://www.ibm.com/developerworks/br/library/os-springroo5/index.html