Simplificando persistência de Dados com Apache DeltaSpike Data

Neste post veremos como simplificar nossas persistências de dados sem ter que escrever varias linhas de códigos para operações comuns como um CRUD .


Introdução ao Apache DeltaSpike

Apache DeltaSpike é uma coleção de extensões CDI portáveis que fornecem recursos úteis para desenvolvedores Java .

DeltaSpike consiste de um módulo CORE e vários módulos OPCIONAIS provendo funcionalidades adicionais para nossas aplicações.

Os módulos incluem recursos para segurança aprimorada com controle de tipo seguro sobre invocações de método, integração com agendamentos, injeção de objetos CDI em validadores, um contexto e escopo transacional e muito mais.

O DeltaSpike também fornece controle de inicialização e desligamento de contêineres CDI em aplicativos Java SE.

Como uma extensão CDI, o DeltaSpike deve ser usado em conjunto com uma implementação de CDI e suporta tanto o JBoss Weld quanto o Apache OpenWebBeans.

O DeltaSpike é testado em uma variedade de servidores de aplicativos e contêineres habilitados para CDI, incluindo o Apache TomEE, o JBoss AS, o WildFly, o Oracle GlassFish e o Jetty.

Os módulos do DeltaSpike são :

  • Core => Para classes fundamentais e definidora da api do DelstaSpike.
  • Bean Validation => Adicionar suporte CDI no Bean Validation, permitindo assim a criação de métodos ConstraintValidator compatíveis com CDI .
  • Container Control => Para inicialização e encerramento do contêiner CDI .
  • Data => Aprimoramento do JPA com consultas declarativas assim reduzindo boilerplate ao minimo.
  • JPA => Para contexto transacional e escopo
  • JSF => Para integração de CDI com JSF, com configuração de visualização segura, manipulação de múltiplas janelas, novos escopos (WindowScoped, ViewScope, ViewAccessScoped, GroupedConversationScoped) e integração com mensagens “core” DeltaSpike e manipulação de exceção.
  • Partial-Bean => Para implementar um manipulador genérico para substituir implementações manuais de interfaces (ou classes abstratas) .
  • Scheduler => Para integração simples com o Quartz v2 (padrão) ou qualquer outro planejador que suporte expressões cron para classes de tarefa .
  • Security => Para interceptar e verificar segurança em chamadas de método .
  • Servlet => Para integração com a Java Servlet API, permitindo a injeção de objetos de servlet comuns e a propagação de eventos de servlet para o barramento de eventos CDI .
  • Test-Control => Para escrever facilmente testes baseados em CDI

Para esse post iremos utilizar o módulo Data que é o mais conhecido e muito útil, passou a ser o meu preferido após eu fazer uma busca no Google, procurando um alternativa ao Spring Data para Jakarta EE .

Além do módulo Data faremos o uso de :


DeltaSpike Data

O módulo Data fornece recursos para implementar padrões de repositório e, assim, simplificar a camada de repositório.

Os padrões de repositório são ideais para consultas simples que exigem código clichê, permitindo a centralização da lógica de consulta e, consequentemente, reduzindo a duplicação de código e melhorando a testabilidade.


Criando o Projeto

Crie um projeto Maven com seguinte pom.xml :


Criando Beans.xml e Persistence.xml

após criar o projeto, crie dois arquivo xml na pasta “resources/META-INF” conforme mostrado abaixo :


Classes Model

agora daremos inicio na construção das nossas classes, aqui somente será duas classe uma que é a nossa Entity e uma outra para para devolver a resposta para o APP Rest . :

Vamos inicia com a criação da Classe Event.java :

e agora nossa classe ResponseModel.java


Classe EntityManager

Primeiro vamos criar nossa classe Produtora .

O DeltaSpike Data requer um EntityManager exposto via CDI como fazemos na pratica de desenvolvimento de aplicações Jakarta EE , então nossa classe produtora chamada EventProduces é da seguinte forma :

até aqui nada de anormal.

Caso a gente for fazer uso do JTA DATASOURCE , temos que configurar o transactionStrategy adicionando um <alternative> em nosso beans.xml passando a seguinte classe : org.apache.deltaspike.jpa.impl.transaction.BeanManagedUserTransactionStrategy

como não é o nosso caso, não vamos precisar .


Classes Repository

Agora sim que a magia vai acontecer .

Com DeltaSpike Data, é possível fazer um repositório de basicamente de qualquer classe abstrata ou interface. Tudo que temos que fazer é marcar o tipo com uma simples anotação :

@Repository(forEntity = Event.class)
public abstract class EventRepository {
...
}

@Repository(forEntity = Event.class)
public interface EventRepository {
...
}

bacana não ?

A anotação informa à extensão que este é um repositório para a entidade Event. Qualquer método definido no repositório será processado pela estrutura.

A anotação não precisa definir a classe de entidade, mas se houver apenas classes ou interfaces simples, essa é a única maneira de informar à estrutura a qual entidade o repositório está relacionado.

Para simplificar isso, o DeltaSpike Data fornece vários tipos de base como :

  • EntityRepository
  • FullEntityRepository
  • AbstractFullEntityRepository
  • AbstractEntityRepository

aqui a gente so vai ver o uso do EntityRepository, para os outros tipos basta dar uma olhada em sua documentação .

A interface EntityRepository, embora principalmente destinado a manter a lógica de consulta complexa, trabalhar com um repositório e um EntityManager na camada de serviço pode sobrecarregar desnecessariamente o código.

Para evitar isso nos casos mais comuns, o DeltaSpike Data fornece tipos de base que podem ser usados para substituir o gerenciador de entidades.

O tipo base superior é a interface EntityRepository, fornecendo métodos comuns usados com um EntityManager. O código a seguir mostra os métodos mais importantes da interface:

O repositório concreto pode estender essa interface básica. Para nosso repositório Event, isso pode parecer com o seguinte:

muito legal não ?

para quem já usa Spring Data, vai se sentir em casa ao utilizar o DeltaSpike Data, pois é bem semelhante os produtos .

Desta forma simplificou bastante na hora de construirmos nossos projeto, pois ganhamos mais produtividade e podemos focar na regras de negócios sem ter que ficar criando métodos comuns que usamos em nosso dia a dia .

na linha 13 podemos ver o que a documentação do DeltaSpike chama de “Query Method Expression” , olhando para o nome do método podemos ver claramente o que ele faz . Aqui o nome do método é a implementação para devolver apenas um “Speaker” .

O DeltaSpike Data pode traduzir nomes de métodos seguindo um determinado formato e gerar diretamente a implementação da consulta a partir dele (em formato semelhante a EBNF):

(Entity|Optional<Entity>|List<Entity>|Stream<Entity>) (prefix)(Property[Comparator]){Operator Property [Comparator]}

Ou em palavras mais concretas:

O método de consulta deve retornar uma entidade, um opcional de uma entidade, uma lista de entidades ou um fluxo de entidades.

Ele deve começar com o prefixo findBy (ou relacionado findOptionalBy, findAnyBy, findAll, findFirst ou findTop).

Você pode adicionar mais blocos de propriedade-comparador que precisam ser concatenados por um operador booleano. Isso é um AND ou OR.

Você também pode usar o mesmo método para excluir uma entidade: * Deve começar com a palavra-chave removeBy (ou deleteBy relacionado).

Além de comparadores, também é possível classificar consultas usando a palavra-chave OrderBy, seguida do nome do atributo e da direção (Asc ou Desc) :

List<Person> findByLastNameLikeOrderByAgeAscLastNameDesc(String lastName);

você pode aplicar limites de consulta usando expressões de método. Eles podem ser aplicados usando os prefixos findFirst ou findTop em um método como este:

List<Person> findFirst2ByLastNameOrderByAgeAscLastNameDesc(String lastName);

Além disso podemos fazer uso de paginação com as anotações @FirstResult e @MaxResults :

List<Person> findByNameLike(String name, @FirstResult int start, @MaxResults int pageSize);

DeltaSpike Data tambeḿ suporta Query por anotação. Apesar das expressões de método seja adequadas para consultas simples, mais ela atingem o seu limite quando necessitamos de algo mais complexas.

Outro aspecto é a maneira como você deseja usar o JPA: A abordagem recomendada usando o JPA para obter melhor desempenho é através de consultas nomeadas.

A maneira mais simples de definir uma consulta específica é anotar um método e fornecer a string de consulta JPQL que deve ser executada. No código, isso parece com o exemplo a seguir:

    @Query("select count(p) from Person p where p.age > ?1")
Long countAllOlderThan(int minAge);

também é possivel usar consuta SQL nativa, bastando adicionar um outro argumento :

 @Query(value = "SELECT * FROM PERSON_TABLE p WHERE p.AGE > ?1",     isNative = true)
List<Person> findAllOlderThan(int minAge);

para explorar mais coisas sobre o DeltaSpike Data, consulte a documentção.


Classes Controler , Pre-Boot, Boot

Agora vamos criar uma classe que vai persistir alguns dados na nossa base quando a aplicação subir e em seguida criaremos nosso rest Controler.

Vamos inicia com a criação da Classe Event.java :

aqui a nossa classe contem uma lista com alguns eventos para serem persistidos .

Na linha 19 a gente faz o uso do nosso repositório EventRepository que esta sendo injetado via CDI com a anotação @Inject e em seguida dentro do método init() chamamos o método save() do nosso repositório .

e agora nossa classe controle fica da seguinte forma :

e agora nossa última classe para iniciar nossa aplicação :

com tudo pronto, basta a gente gerar o nosso Uber/Fat Jar com o seguinte comando dentro da pasta do projeto :

mvn clean package payara-micro:bundle && mvn payara-micro:start

e abrir o navegador com localhost:8080 e exibindo a seguinte tela :

indo na primeira aba podemos consultar todos os eventos persistidos em nosso H2 :

Bem isso é tudo, espero que os leitores tenham gostado de conhecer o DeltaSpike Data como alternativa ao Spring Data em um ambiente Jakarta EE .

Código-fonte : https://github.com/Daniel-Dos/DanielDiasjava-Blog/tree/master/ProjetoDeltaSpike

REFERÊNCIAS