segunda-feira, 18 de dezembro de 2017

CDI - Injeção de Dependência e Contexto

O que é CDI? Para que serve? E como usar? Bom, essas três perguntas eu pretendo responder nesse post. O CDI é a especificação Java que define a injeção de dependência e inversão de controle para aplicações JavaEE. Como o CDI é uma especificação, existem implementações, e como é comum no Java, existe a implementação de referência, que nesse caso é a Weld.

O que esta especificação define? Basicamente ela trata sobre injeção de dependência (DI) e inversão de controle (IoC) no contexto e escopos de uma aplicação JavaEE. Mas o que é injeção de dependência e inversão de controle? Bom, essas duas coisas andam bem juntas.

Injeção de dependência é tornar disponível a instância de uma classe quando precisamos dela. Isso ocorre quando dentro de uma classe fazemos algo como:

MinhaClasse c = new MinhaClasse();

Nesse momento estamos dizendo que a classe a qual estamos depende da classe MinhaClasse. A questão é que isso é uma coisa corriqueira e que sempre precisamos fazer, então, por quê não tornar isso automático? Aí entra a questão da Inversão de Controle. Vamos passar a responsabilidade de colocar essa instância para o container ao invés de nós ficarmos dando um “new” sempre que quisermos usar uma classe. Dessa forma, passamos a tratar o exemplo acima da seguinte maneira:

@Inject
MinhaClasse c;

Dessa forma, quando o container perceber que precisamos da classe c, ele irá colocar a instancia para nós. Mas para isso funcionar, precisamos aprender umas coisinhas ainda!

Primeiro, para um projeto estar apito a usar o CDI, precisamos adicionar um arquivo de configuração chamado beans.xml que deve ficar dentro de /main/webapp/WEB-INF/. Esse arquivo deve conter o seguinte trecho de código:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="2.0" bean-discovery-mode="all">

</beans>

Caso seja um módulo EJB ou JAR, o arquivo deve estar no diretório META-INF/. Note que temos esse atributo bean-discovery-mode="all" que informa para o CDI que todas as classes serão consideradas beans CDI. Outras opções para esse valor são: annotated - habilita apenas as classes anotadas - e none que desabilita o CDI. Mas para que a injeção funcione, toda classe que quisermos que seja um bean CDI deve ser pública e possuir um construtor padrão.

No pom.xml devemos colocar:

<!-- Weld (implementacao do CDI) -->
<dependency>
       <groupId>javax.enterprise</groupId>
       <artifactId>cdi-api</artifactId>
       <!-- Use version 2.0 for Weld 3 -->
       <version>2.0</version>
</dependency>

Quando queremos usar um Bean CDI em uma página JSF, precisamos anotar esse Bean com a anotação @Named. Isso permite ao bean CDI ter um nome que pode ser usado pela Expression Language  do JSF. Essa anotação pode receber uma String que dá a classe um nome específico para ser usado nas páginas xhtml. Caso não seja especificado, o nome padrão é o nome da classe com a primeira letra minúscula.

E quando não queremos que determinada classe ou pacote não seja injetada via CDI? Temos algumas formas de fazer isso: Via anotação @Vetoed ou via configuração no arquivo beans.xml.

Usando a anotação temos o seguinte:

@Vetoed
public class MinhaClasse implements MinhaInterface {
         ...
}

Isso fará com que essa classe seja desconsiderada pelo CDI e ela não poderá ser injetada em outras classes. Caso queira que todo o pacote seja desconsiderado, a anotação @Vetoed pode ser usada sobre o pacote:

@Vetoed
package br.com.utils;

public class MinhaClasse implements MinhaInterface {
         ...
}

Via anotação teremos o seguinte:

<beans ... >
<scan>
   <!-- posso excluir apenas a classe: -->
   <exclude name="br.com.utils.MinhaClasse.java"/>
   <!-- ou posso excluir todas as classes do pacote utils: -->
   <exclude name="br.com.utils.*"/>
   <!-- ou posso excluir o pacote util completo, incluindo subpacotes: -->
   <exclude name="br.com.utils.**">
</scan>
</beans>

É possível ainda usar condicionais para definir quando uma classe ou pacote deve ser desconsiderado para injeção usando as TAG’s <if-system-property>, <if-class-available> e <if-class-not-available>, como mostrado a seguir:

<beans ...>
 <scan>
  <exclude name="br.com.rest.*" />
   <exclude name="br.com.faces.**">
    <if-class-not-available name="br.com.MeuBean"/>
   </exclude>
   <exclude name="br.com.dao.*">
    <if-system-property name="propriedade" value="valor"/>
    </exclude>
   <exclude name="br.com.ejb.**">
    <if-class-available name="javax.enterprise.inject.Model"/>
     <if-system-property name="exclude-ejbs"/>
   </exclude>
 </scan>
</beans>

Contexto e Escopos:

O contexto é responsável pelo ciclo de vida e a visibilidade dos beans CDI dentro dos escopos definidos. Os beans CDI tem os seguintes escopos:

·       @RequestScoped – O bean tem o escopo da requisição.
·       @ConversationScoped – O bean com escopo definido pelo desenvolvedor na aplicação.
·   @ViewScoped – do pacote javax.faces.view.ViewScoped, tem o escopo de uma view. Enquanto estiver na mesma tela, o bean estará disponível. Veio para substituir o ViewScoped do JSF.
·    @SessionScoped – O bean tem o escopo da sessão do usuário. É considerado um escopo longo e deve ser usado com cuidado.
·     @ApplicationScoped – O bean fica instanciado durante todo o tempo que a aplicação estiver disponível. É o escopo mais longo e também deve ser usado em poucos casos.

     Fora estes escopos, existe um que é o principal escopo do CDI - @Dependent, digo isto porque quando nenhum escopo é definido explicitamente ele é usado por padrão no CDI (o que geralmente ocorre com a maioria das classes). Este escopo delibera que uma classe quando definida com ele, ao ser injeta em outra classe, terá o mesmo escopo da classe à qual foi injetado. Em outras palavras, quando injetamos uma instância de uma classe com escopo @Dependent dentro de uma instância de uma classe que tenha o escopo de Sessão por exemplo, a classe com o escopo @Dependent passa a ter escopo de Sessão automaticamente.

            Transações Gerenciadas pelo Container

A versão do JTA 1.2  introduz a anotação @javax.transaction.Transactional. Essa anotação possibilita que as aplicações possam demarcar os limites de uma transação declarativamente. Isto é feito utilizando beans CDI gerenciados, assim como as classes definidas como Managed beansServletsJAX-RS e os endpoints JAX-WS.

As anotações podem ser especificadas tanto em nível de método como em nível de classe, no entanto, as anotações em nível de método sobrescrevem aquelas que estão em nível de classe.

Segue o exemplo do uso na classe:

@Transactional
public class MinhaClasse {
   //...
}

Segue o exemplo do uso no método:

public class MinhaClasse {
   public void consultar() {
       //...
   }

   @Transactional
   public void incluir() {
     //...
   }
}

Esse controle de transação é fornecido através de uma implementação de interceptores do CDI que realizam o cancelamento ou recuperação da transação quando necessário.

O elemento TxType da anotação @Transactional fornece tipos de transação equivalente a semântica utilizada nos atributos de transação do EJB. Deve ser especificado da seguinte forma: @Transactional(TxType.REQUIRES_NEW) Segue uma tabela com os tipos suportados:

TxType
Fora de um contexto de Transação
Dentro de um contexto de Transação
REQUIRED (default)
O interceptor deve iniciar uma nova transação JTA, o método de execução do Managed Bean deve então continuar dentro desde contexto de transação e a transação deve ser completada pelo interceptor.
O método de execução do Managed Bean deve continuar dentro deste contexto de transação.
REQUIRES_NEW
O interceptor deve iniciar uma nova transação JTA, o método de execução do Managed Bean deve então continuar dentro deste contexto de transação, e a transação deve ser completada pelo interceptor.
O contexto de transação corrente deve ser suspenso, uma nova transação JTA será iniciada, o método de execução do Managed Bean deve então continuar dentro deste contexto de transação, a transação deve ser completada, e a transação anterior que foi suspensa deve ser retomada.
MANDATORY
Uma TransactionalException com uma TransactionRequiredException aninhada deve ser lançada.
O método de execução do Managed Bean continuará sob o contexto.
SUPPORTS
O método de execução do Managed Bean deve continuar fora de um contexto de transação.
O método de execução do Managed Bean deve continuar dentro deste contexto de transação.
NOT_SUPPORTED
O método de execução do Managed Bean deve continuar fora de um contexto de transação.
O contexto de transação corrente deve ser suspenso, o método de execução do Managed Bean deve continuar fora de um contexto de transação, e a transação anterior suspensa deve ser retomada pelo interceptor que suspendeu essa transação após o método de execução ser completado.
NEVER
O método de execução do Managed Bean deve continuar fora de um contexto de transação.
Uma TransactionalException com uma ValidTransactionException aninhada deve ser lançada.
fonte: Devmedia 

Por padrão, no CDI as exceções checadas não resultam em rollback, como é também no EJB como mostro nessa postagem. Porém instâncias de RuntimeException e suas subclasses resultam em rollback da transação.

Mas assim como no EJB existe uma forma explicita de forçar o rollback nas exceções verificadas, no CDI também é possível fazer. O elemento “rollbackOn” permite que você especifique as classes de exceções que mesmo quando verificadas no bloco try/catch devem fazer o rollback.

@Transactional(rollbackOn={Exception.class})

E como é possível especificar as classes de exceções que forçarão o rollback, também podemos especificar as classes que não devem causar rollback através do elemento “dontRollbackOn”.

@Transactional(dontRollbackOn={IllegalStateException.class})

Para concluir o assunto sobre transações, existe uma anotação que garante que uma única instância de um bean será usada em todo contexto da transação: @TransactionalScoped. Toda classe marcada com essa anotação tem seu ciclo de vida delimitado para a transação JTA ativa no momento. Se durante a transação, múltiplas instâncias desse bean são injetadas em diferentes classes, o CDI refere-se a mesma instância, assegurando que apenas uma instância do bean seja utilizada e que ela mantenha suas propriedades valoradas.

import javax.transaction.TransactionScoped;

@TransactionScoped
public class TestTransactionalScopeBean {
    //...
   

}

       




Bibliografia:




terça-feira, 12 de dezembro de 2017

REGEX – Java

       Expressões regulares nos ajudam a identificar textos por padrões. Isso é muito usado para fazer validações e trabalhar com leitura/escrita de arquivos, entre outras coisas.

Modificadores:

·       (?i) – Ignora letras maiúsculas e minúsculas;
·       (?x) – Comentários;
·       (?m) – Múltiplas linhas;
·       (?s) – Dotall;

Uso dos modificadores:

“Java”.matches(“(?i)java”) – true.
“Java”.matches(“(?ims)java”) – true.

Metacaracteres

·       . (ponto) – Qualquer caractere;
·       \d – Dígitos [0-9];
·       \D – Não é dígito;
·       \s – Espaços;
·       \S – Não é espaço;
·       \w – Letras e números [a-z,A-Z,0-9];

Uso dos metacaracteres:

“J”.matches(“(?i)\\d”) – false.
“#”.matches(“.”) – true.
“J”.matches(“\\w”) – true.

Obs: note o uso do caractere de escape “\” quando necessário.

Quantificadores

·       * (asterisco) – Qualquer quantidade;
·       ? – 0 ou 1 vez;
·       + – 1 ou mais vezes;
·       {n} – Exatamente n vezes;
·       {n,} – Pelo menos n vezes;
·       {n,m} – Entre n e m vezes;

Uso dos quantificadores:

“60.282-010”.matches(“\\d{2}\.\\d{3}-\\d{3}”) – true.
“@#%”.matches(“.{2,3}”) – true.
“Java123”.matches(“\\w*”) – true.

Metacaracteres de Fronteira

·       ^ – Inicia com;
·       $ – Finaliza com;
·       | – Ou;

Uso dos metacaracteres de fronteira:

“Java123”.matches(“^Java.*”) – true.
“Java123”.matches(“.*123$”) – true.

Agrupadores

·       [...] – Agrupamento;
·       [a-z] – Alcance;
·       [a-e][i-u] – União;
·       [a-z&&[aeiou]] – Interseção;
·       [^abc] – Exceção;
·       [a-z&&[^m-p]] – Subtração;
·       \x

Uso dos agrupadores:

"Java123”.matches(“(?i)[a-z]*”) – true.

Converters do JPA

O JPA 2.1 trouxe conversores que nos permitem especificar como mapear tipos de dados. Um conversor deve implementar a interface javax.persistence.AttributeConverter<X,Y>, passando a classe da entidade em X e classe do banco de dados em Y. O conversor também precisa ser anotado com javax.persistence.Converter.

Ao implementar essa interface, dois métodos são requeridos: o convertToDatabaseCollumn que é usado pelo JPA para persistir o atributo no banco de dados e o convertToEntityAtribute que é usado para trazer os dados do banco para o Java.

Os conversores funcionam basicamente como os conversores do JSF, e podem ser usados de 2 maneiras, com o atributo autoApplay=true na anotação @Converter, fazendo com que o conversor seja aplicado automaticamente em todos os casos, ou aplicando o conversor diretamente na propriedade nas entidades - @Convert(Converter = NomeDaClasse.class) – conforme necessidade.

          Podem ser usados para mapear novos tipo de dados que o JPA ainda não mapeia sozinho como é o caso do LocalDate e LocalDateTime, mapear Enums, quando se quer por exemplo, guardar um atributo do enum ao invés da sua representação ORDINAL ou STRING e até para criptografia, como vou mostrar em um outro post.

          Como exemplo vou me deter ao converter para o LocalDate e um converter para guardar uma propriedade de um Enum. Vamos ao primeiro exemplo:

@Entity
public class Pedido {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id", updatable = false, nullable = false)
        private Long id;
       
        @Column
        private LocalDate dataPrevisaoEntrega;
                
        ...
       
}

          Segue o conversor:

@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
       
    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return (localDate == null ? null : Date.valueOf(localDate));
    }

    @Override
    public LocalDate convertToEntityAttribute(Date sqlDate) {
        return (sqlDate == null ? null : sqlDate.toLocalDate());
    }
}

         
          Perceba que no exemplo, na anotação @Converter foi passado o atributo autoApplay=true. Isso faz com que o conversor seja aplicado automaticamente em todos os casos. Quando esse atributo é falso, você fica responsável por informar ao JPA sempre que desejar usá-lo, anotando a propriedade com @Convert e passando a classe do conversor como segue:

@Column
@Convert(Converter = LocalDateConverter.class)
private LocalDate dataPrevisaoEntrega;

          Vamos para o segundo exemplo, onde temos o Enum, o Converter e como aplicá-lo:      

public enum Veiculo {
   
    BUS("B"), CAR("C"), TRAIN("T"), PLANE("P");

    private String codigo;

    private Veiculo(String codigo) {
        this.codigo = codigo;
    }

    public String getCodigo() {
        return codigo;
    }

    public static Veiculo fromCodigo(String codigo) {
        switch (codigo) {
        case "B":
            return Veiculo.BUS;

        case "C":
            return Veiculo.CAR;

        case "T":
            return Veiculo.TRAIN;

        case "P":
            return Veiculo.PLANE;

        default:
            throw new IllegalArgumentException("codigo [" + codigo
                    + "] não suportado.");
        }
    }
}
         
          O converter para o Enum segue abaixo:

@Converter(autoApply = true)
public class VeiculoConverter implements AttributeConverter<Veiculo, String> {

    @Override
    public String convertToDatabaseColumn(Veiculo Veiculo) {
        return Veiculo.getCodigo();
    }

    @Override
    public Veiculo convertToEntityAttribute(String dbData) {
        return Veiculo.fromCodigo(dbData);
    }

}
         
          E então basta usar o enum:

@Entity
public class Viagem {
    
    private Veiculo veiculo;

    ...
}

          Pronto, sempre que precisarmos especificar como uma classe deve ser salva no banco podemos usar os conversores. Vou compartilhar um site muito bom para quem quer se aprofundar no JPA e no qual me baseei para este artigo: