Archive for abril, 2015

JPA 2.1 – AttributeConverters na prática com Hibernate

sexta-feira, abril 10th, 2015

Depois de um longo e tenebroso inverno, voltamos às atividades.

Este post é focado em quem sabe o que é um AttributeConverter e quer usar na prática, escrito em um tom irônico :-)

Eis que finalmente a spec do JPA permite criar, de forma portável, conversores para suportar tipos arbritários. E como trabalhamos com Java 8, queremos usar java.time.LocalDate, java.time.YearMonth e afins. Além disso, queremos enums que tenham persistência com mnemômicos (ex: “M” para “MASCULINO” e não “MASCULINO” na coluna do banco). Na teoria, basta escrever os converters. Já na prática…

Você vai e escreve sua primeira implementação. Aí você vai fazer os testes e pensa… “Mas e null, como é tratado?” Você lê o Javadoc e… não fala! Ok, vamos ver o que o Hibernate faz na prática com este caso: pra o 4.3.8, versão atual de agora, o conversor não é chamado para valores null. Mas será que continuará assim? Procurando no Google, você descobre que a próxima versão, segundo a HHH-8697, irá chamar o conversor para valores null. Ok, então vamos criar uma superclasse utilitária chamada NullSafeAttributeConverter que para null, retorna null e chama um método protected para quando o valor não é nulo.

Aí, você muda seus conversores e tudo para de funcionar. Algo como:

Caused by: org.hibernate.AssertionFailure: Could not extract ParameterizedType representation of AttributeConverter
definition from AttributeConverter implementation class

E aí você descobre via HHH-8854 que o Hibernate não sabe resolver os tipos do seu conversor quando há superclasses genéricas. Ou seja, tem que fazer extends NullSafeAttributeConverter<LocalDate, Date> implements AttributeConverter<LocalDate, Date>.

Ufa, vamos tentar fazer os conversores de enum. Pode-se usar uma interface com default methods com uma API ou anotações e ter um conversor genérico. Só que… e como saber a subclasse específica da Enum em questão para fazer a conversão (ex: Sexo ou Estado)? Não tem como! Ah, mas via API do Hibernate tem como… Mas não dá pra registrar automaticamente para todas as enums; teria que fazer um registro por tipo de qualquer forma. Qual a solução? Acabamos usando processadores de anotações para gerar o código dos AttributeConverters com @Converter(autoApply = true).

Dá trabalho? Dá. Porém, quando funciona é lindo e produtivo!

E você, teria interesse e/ou gostaria de colaborar com um projeto open-source com estas implementações?