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
Comentários
Postar um comentário