Проблема, которую я пытаюсь решить
Я пытаюсь реализовать отображение enum для Hibernate. До сих пор я исследовал доступные варианты, и оба значения @Enumerated(EnumType.ORDINAL)
и @Enumerated(EnumType.STRING)
показались мне неадекватными. @Enumerated(EnumType.ORDINAL)
, кажется, очень подвержен ошибкам, так как простое переупорядочение констант enum может испортить отображение, и @Enumerated(EnumType.STRING)
тоже недостаточно, так как база данных, с которой я работаю, уже полна значений для отображения,и эти значения не соответствуют именам моих констант enum (значения являются строками / целыми числами на иностранных языках).
В настоящее время все эти значения сопоставляются со свойствами String / Integer. В то же время свойства должны разрешать только ограниченный набор значений (представьте себе свойство meetingStatus
, допускающее строки: PLANNED
, CANCELED
и DONE
. Или другое свойство, допускающее ограниченный набор значений типа Integer:1
, 2
, 3
, 4
, 5
).
Моя идея состояла в том, чтобы заменить реализацию перечислениями для повышения безопасности типов кода. Хорошим примером, когда реализация String / Integer может привести к ошибкам, является параметр метода String, представляющий такое значение - с String все идет туда. С другой стороны, наличие типа параметра Enum обеспечивает безопасность во время компиляции.
На данный момент мой лучший подход
Единственное решение, которое, казалось, удовлетворяло моим потребностям, было реализовать пользовательский javax.persistence.AttributeConverter
с @Converter
аннотация для каждого перечисления. Поскольку моей модели потребовалось бы довольно много перечислений, написание пользовательского конвертера для каждого из них стало казаться действительно безумным. Поэтому я искал общее решение проблемы -> как написать универсальный конвертер для любого типа перечисления. Следующий ответ очень помог здесь: https://stackoverflow.com/a/23564597/7024402. Пример кода в ответе предусматривает несколько общую реализацию, но для каждого перечисления все еще необходим отдельный класс преобразователя. Автор ответа также продолжает:
"Альтернативой может быть определение пользовательской аннотации, исправление поставщика JPA для распознавания этой аннотации. Таким образом, вы можете проверить тип поля при созданииотображая информацию и передавая необходимый тип enum в чисто общий конвертер. "
И это то, что, я думаю, меня заинтересует. К сожалению, я не смогу найти больше информации об этом, и япотребуется немного больше руководств, чтобы понять, что нужно сделать и как он будет работать с этим подходом.
Текущая реализация
public interface PersistableEnum<T> {
T getValue();
}
public enum IntegerEnum implements PersistableEnum<Integer> {
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6);
private int value;
IntegerEnum(int value) {
this.value = value;
}
@Override
public Integer getValue() {
return value;
}
}
public abstract class PersistableEnumConverter<E extends PersistableEnum<T>, T> implements AttributeConverter<E, T> {
private Class<E> enumType;
public PersistableEnumConverter(Class<E> enumType) {
this.enumType = enumType;
}
@Override
public T convertToDatabaseColumn(E attribute) {
return attribute.getValue();
}
@Override
public E convertToEntityAttribute(T dbData) {
for (E enumConstant : enumType.getEnumConstants()) {
if (enumConstant.getValue().equals(dbData)) {
return enumConstant;
}
}
throw new EnumConversionException(enumType, dbData);
}
}
@Converter
public class IntegerEnumConverter extends PersistableEnumConverter<IntegerEnum, Integer> {
public IntegerEnumConverter() {
super(IntegerEnum.class);
}
}
Этокак мне удалось добиться реализации частично универсального конвертера.
ЦЕЛЬ: избавиться от необходимости создавать новый класс конвертера для каждого перечисления.