terça-feira, 12 de dezembro de 2017

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:


Nenhum comentário:

Postar um comentário