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 AttributeConverter
s 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?
Muito bom Michael, tenho interesse em colaborar.