Mapeando Enuns com JPA.





O JPA (Java Persistence API)  fornece duas formas  para mapeamento de enumerações em entidades @Enumerated e @MapKeyEnumerated.
Os valores das enumerações podem ser persistidos no banco respeitando uma das duas estratégias definidas em javax.persistence.EnumType:
·         ORDINAL -  persistido de acordo com a posição da constante na classe enum;

·         STRING -  persistido de acordo com o nome da constante na classe enum.

Exemplo: ORDINAL


 @Entity  
 public class Pessoa {  
      @Id  
      private Long id;  
      @Enumerated  
      private TipoPessoa tipo;  
      public Pessoa() {  
      }  
      public Long getId() {  
           return id;  
      }  
      public void setId(Long id) {  
           this.id = id;  
      }  
      public TipoPessoa getTipo() {  
           return tipo;  
      }  
      public void setTipo(TipoPessoa tipo) {  
           this.tipo = tipo;  
      }  
 }  



 public enum TipoPessoa {  
      FISICA,  
      JURIDICA  
 }  

No exemplo acima. O atributo tipo é uma enum, como não informamos nada além da anotação @Enumerated. O tipo de persistência assumido é o default ORDINAL.
Isso significa  que no banco teremos uma coluna INTEGER tipo com os seguintes valores:
·         NULL = null;
·         0 = FISICA;

·         1 = JURIDICA;



Exemplo: STRING

 @Entity  
 public class Pessoa {  
      @Id  
      private Long id;  
      @Enumerated(EnumType.STRING)  
      private TipoPessoa tipo;  
      public Pessoa() {  
      }  
      public Long getId() {  
           return id;  
      }  
      public void setId(Long id) {  
           this.id = id;  
      }  
      public TipoPessoa getTipo() {  
           return tipo;  
      }  
      public void setTipo(TipoPessoa tipo) {  
           this.tipo = tipo;  
      }  
 }  


No exemplo acima. O atributo tipo é uma enum (a mesma do exemplo anterior), como informamos javax.persistence.EnumType.STRING os valores serão persistidos com base no nome das constantes da enun em uma coluna CHAR do banco
·         NULL = null;
·         ‘FISICA’ = FISICA;

·         ‘JURIDICA’ = JURIDICA;

Porém muitas vezes trabalhamos com bases de dados legadas. As informações já estão persistidas. E muitas vezes da maneira que desejamos. Por exemplo, no exemplo anterior a coluna tipo poderia ser do tipo CHAR, porém contendo apenas F ou J. Não seria legível a nível de código criar uma enumeração com as constantes F ou J.

Para solucionar esse problema. Existem duas estratégias. O uso de AttributeConverter ou Custom type.


AttributeConverter 



Enumerações podem ser mapeadas com usando JPA 2.1 AttributeConverter. Conforme o exemplo abaixo:


 public enum TipoPessoa {  
      FISICA ("F"),  
      JURIDICA ("J");  
      private final String codigo;  
      TipoPessoa(String codigo) {  
           this.codigo = codigo;  
      }  
      public String getCodigo() {  
           return codigo;  
      }  
      public static TipoPessoa getTipoPessoa(String codigo) {       
           if("F".equals(codigo)) {  
                return FISICA;  
           }  
           if("J".equals(codigo)) {  
                return JURIDICA;  
           }  
           return null;  
      }  
 }  


 @Entity  
 public class Pessoa {  
      @Id  
      private Long id;  
      @Basic  
      @Convert( converter=TipoPessoaConverter.class )  
      private TipoPessoa tipo;  
      public Pessoa() {  
      }  
      public Long getId() {  
           return id;  
      }  
      public void setId(Long id) {  
           this.id = id;  
      }  
      public TipoPessoa getTipo() {  
           return tipo;  
      }  
      public void setTipo(TipoPessoa tipo) {  
           this.tipo = tipo;  
      }  
 }  


 @Converter  
 public class TipoPessoaConverter implements AttributeConverter<String, TipoPessoa> {  
      @Override  
      public TipoPessoa convertToDatabaseColumn(String codigo) {  
           return TipoPessoa.getTipoPessoa(codigo);  
      }  
      @Override  
      public String convertToEntityAttribute(TipoPessoa tipo) {  
           if(null == tipo) {  
                return null;  
           }  
           return tipo.getCodigo();  
      }  
 }  

No exemplo acima teremos as colunas salvas da seguinte forma:
·         NULL = null;
·         ‘F’ = FISICA;

·         ‘J’ = JURIDICA


Custom type


Para solucionar o problema anterior, nós podemos utilizar o Hibernate Custom type. Conforme o exemplo abaixo:


 @Converter  
 public class TipoPessoaType extends AbstractSingleColumnStandardBasicType<TipoPessoa> {  
      public static final TipoPessoaType INSTANCE = new TipoPessoaType();  
      private TipoPessoaType() {  
           super(StringTypeDescriptor.INSTANCE, TipoPessoaTypeDescriptor.INSTANCE);  
      }  
      public String getName() {  
           return "tipoPessoa";  
      }  
      @Override  
      protected boolean registerUnderJavaType() {  
           return true;  
      }  
 }  
 public class TipoPessoaTypeDescriptor extends AbstractTypeDescriptor<TipoPessoa> {  
      public static final TipoPessoaTypeDescriptor INSTANCE = new TipoPessoaTypeDescriptor();  
      public String toString(TipoPessoa tipo) {  
           return tipo == null ? null : tipo.getCodigo();  
      }  
      public TipoPessoa fromString(String codigo) {  
           return TipoPessoa.getTipoPessoa(codigo);  
      }  
      public <X> X unwrap(TipoPessoa tipo, Class<X> type, WrapperOptions options) {  
           return StringTypeDescriptor.INSTANCE.unwrap(  
                     tipo == null ? null : tipo.getCodigo(),  
                     type,  
                     options  
           );  
      }  
      public <X> TipoPessoa wrap(X value, WrapperOptions options) {  
           return StringTypeDescriptor.INSTANCE.wrap( value, options );  
      }  
 }  
 @Entity  
 public class Pessoa {  
      @Id  
      private Long id;  
      @Basic  
      @Type( type = TipoPessoaType.class )  
      private TipoPessoa tipo;  
      public Pessoa() {  
      }  
      public Long getId() {  
           return id;  
      }  
      public void setId(Long id) {  
           this.id = id;  
      }  
      public TipoPessoa getTipo() {  
           return tipo;  
      }  
      public void setTipo(TipoPessoa tipo) {  
           this.tipo = tipo;  
      }  
 }  

No exemplo acima, novamente teremos a coluna salva da seguinte forma:
·         NULL = null;
·         ‘F’ = FISICA;

·         ‘J’ = JURIDICA

Referencias


Comentários

Postagens mais visitadas deste blog

Engenharia de Agentes de IA com LangChain4j, Spring Boot e Gemini

Micro Profile JavaEE com Wildfly Swarm