У меня есть объект Generi c, который я хочу сохранить с помощью JPA, чтобы его значение generi c сохранялось в одном столбце jsonb
. Упрощенный класс сущности выглядит следующим образом:
@Entity
public class Generic<T> {
@Id
private String name;
private Type type;
private T value; // want to store it in jsonb column
// ... constructros, getters
}
type
однозначно идентифицирует класс значения generi c, и допускается несколько типов с одним и тем же классом:
public enum Type {
TYPE1(Double.class),
TYPE2(Double.class),
TYPE3(Coordinate.class),
...
TYPEN(Double.class);
private Class<?> aClass;
TelemetrySignal(Class<?> aClass) {
this.aClass = aClass;
}
Class<?> getClass() {
return aClass;
}
}
Мне не удалось найти способ сохранения такого обобщенного класса c с использованием Hibernate как есть. Я нашел альтернативные способы и обходные пути, но они не выглядят идеальными для меня. Я рассмотрел варианты:
Пометить Generic
как абстрактный и аннотировать его @MappedSuperclass
, использовать наследование одной таблицы и для каждого возможного класса значений создать производный класс, который сохраняет значения как json
в тот же столбец jsonb
и загружает в конкретный класс. Я бы выбрал этот вариант для простой иерархии, но я ожидаю много классов. А для дополнительного нового класса значения требуется новый производный класс.
Установите тип значения как JsonNode
и пометьте его класс типа как com.vladmihalcea.hibernate.type.json.JsonBinaryType
. В этом случае требуется только один класс Java, но недостатком является то, что мне приходится взаимодействовать с JsonNode
в остальной части моего кода. Я должен конвертировать туда и обратно, когда требуется информация о классе, например, чтобы передать ее соответствующему обработчику.
Также я рассмотрел варианты, но не смог реализовать:
Я попытался реализовать свой собственный org.hibernate.type.Type
и использовал com.vladmihalcea.hibernate.type.ImmutableType
, чтобы упростить его. Идея состоит в том, чтобы при обработке столбца value
посмотреть столбец type
и десериализовать значение в соответствующий класс. Но мне не удалось правильно реализовать T get(ResultSet rs, String[] names,...)
, поскольку я получаю только имя текущего столбца для значения и не могу получить значение столбца type
из ResultSet
(Hibernate создает псевдонимы для всех столбцов).
Я пытался использовать два поля: @Transient T value
и JsonNode genericValue
. Идея состояла в том, чтобы преобразовать значение из @Transient T value
в JsonNode genericValue
в методе @PrePersist
и преобразовать JsonNode
в @Transient T value
, используя поле type
с информацией о классе в методе @PostLoad
. Но оказалось, что @Transient
поля являются пустыми в @PrePersist
методах.
В настоящее время я остановился на 2-м варианте, но я рассматриваю 5-й вариант: создать собственный репозиторий для этого и использовать JdbcTemplate
вместо Hibernate только для этого класса. Это определенно возможно, потому что я могу получить столбец type
из ResultSet
и десериализовать значение в соответствующий класс. Но у меня все еще есть шанс, что кто-то предложит альтернативный вариант, используя Hibernate. Есть идеи?