Mapear Enumerações na JPA

Trabalhar com enumeração no Java permite ao desenvolvedor e arquiteto estabelecer um ambiente fortemente tipado, além de trabalhar com uma lista de valores específicos e com tamanho finito. No entanto, quando o assunto é levado além das fronteiras da aplicação Java, algumas complicações podem ser encontradas, principalmente no que se diz respeito à normalização de bancos de dados. Com isso, veremos a seguir uma técnica para mapear enumerações na JPA de forma eficiente e deixar todo mundo feliz 🙂

Uma classe enumerada é derivada da classe java.lang.Enum e pode ser facilmente criada, veja um exemplo:

Observe que a keyword enum foi utilizada na assinatura da classe para indiciar a criação do enumerador. Em seguida, foram definidos os elementos do enum. Observe que cada elemento é separado por vírgula. Cada elemento inserido possui um indexador inteiro dentro da classe, e assim como em listas, o primeiro elemento é representado por 0. Para recuperar o valor do índice de um elemento, utiliza-se o método ordinal().

Também é possível recuperar o valor do elemento em String por meio do método name().

Sabendo disto, podemos iniciar os trabalhos com o mapeamento de enumeradores com a JPA. Para isto, utiliza-se a anotação javax.persistence.Enumerated. Esta anotação trabalha exatamente com essas duas formas de recuperação de valores supracitadas. Veja um exemplo básico da anotação:

Caso a anotação seja utilizada sem argumentos, a JPA vai assumir o valor do índice do elemento para persistência, ou seja, se o campo receber um Sexo.MASCULINO como valor, será persistido o índice 0 no banco de dados. Este comportamento também pode ser obtido ao passar como argumento da anotação um EnumType.ORDINAL.

Esta abordagem é constantemente criticada por DBA’s , pois além de ser um valor pouco significante para o negócio, haverá um valor numérico “solto” gravado no banco. Para que este valor ganhe a devida importância, é necessário a criação de um dicionário de dados. Isso é ruim, amigão!

Uma alternativa para o problema dos índices, é passar o nome do elemento numa cadeia de caracteres, ou seja, ao invés de gravar o valor 0, seria gravado MASCULINO, por exemplo. Para isto, é necessário passar como argumento do @Enumerated o valor EnumType.STRING.

Apesar de resolver os problemas de ter uma informação gravada em banco sem o devido valor para o negócio e eliminar a necessidade do dicionário de dados – para este caso -, alguns administradores de dados podem argumentar quanto à normalização do banco e critérios de desempenho, sugerindo a mudança do valor gravado para “M” ou “F”. De fato, é um argumento plausível, pois além de tornar o processo de indexação do campo mais performático, evidentemente gasta-se menos memória para alocar M do que MASCULINO.

Mas pára tudo! A recuperação do índice do elemento não agrega valor para o negócio, mas facilita a manipulação na aplicação, o valor nominal do elemento é bom, mas pode influenciar no desempenho do banco de dados, e além disso o DBA pediu pro valor ser representado por apenas um caractere no banco de dados. Você pensa: “F***”, mas este é o cenário em que o uso de enumerações torna-se muito mais rico e atraente, pois é possível misturar os três cenários e customizar o comportamento do enumerador.

A primeira mudança a se fazer, é refatorar a classe Sexo para que os elementos sejam representados pelos caracteres “M” e “F”. Criaremos também dois métodos para configuração e retorno do elemento específico, baseado num valor recebido.

Agora que temos o enumerador completo, é necessário alterar o mapeamento do campo na JPA. Porém, tenha em mente que a JPA consegue retornar o name ou o ordinal de um campo enum. Logo, será necessário criarmos uma forma de customizar o comportamento do enumerador a fim de persistirmos somente o caractere do elemento. Para isto, deixaremos o atributo do tipo Sexo transiente e passaremos a responsabilidade do valor para um outro atributo do tipo String. Veja como fica:

Agora é só mandar um abraço pro DBA 🙂

Até a próxima.

Written by Raphael Oliveira Neves
Engenheiro de software, evangelista de novas tecnologias e apaixonado por arquitetura e desenvolvimento de software utilizando Java.