TL; DR
Есть ли способ чисто передать некоторые аргументы объекту, созданному в спящем режиме, после загрузки?
Что у меня есть
@Entity
public class MyEntity {
@Lob
private String mapAsJson;
@Transient
private Map<Long, Double> map = new HashMap<>();
// Getters, null-checks, and all that. Always keeping these two in sync, or at least before it persists
}
Что я хочу
@Entity
public class MyEntity {
@Embedded
private MyEmbedded<Long, Double> embeddedMap = new MyEmbedded<>();
}
@Embeddable
public class MyEmbedded<K, V> {
@Lob
private String mapAsJson;
@Transient
private final Map<K, V> map = new HashMap<>();
@PreUpdate @PrePersist
private void storeAsJson() {
// JsonUtil encapsulates com.fasterxml.jackson.databind.ObjectMapper logic
mapAsJson = JsonUtil.toString(map);
}
@PostLoad
private void loadFromJson() {
map.clear();
if (mapAsJson != null)
// JsonUtil encapsulates com.fasterxml.jackson.databind.ObjectMapper logic
map.putAll(JsonUtil.fromString(mapAsJson, HashMap.class));
}
}
Зачем мне это
Просто для красивой инкапсуляции гидратация в / из этого рабочего объекта карты. Если бы у меня было еще 2 таких поля, это было бы много повторяющегося кода. Это, конечно, очень специфический пример c, но его можно распространить на другие объекты, кроме карты.
Почему это не работает
Этот JsonUtil.fromString(mapAsJson, HashMap.class)
в основном угадывает типы. В настоящее время он возвращает карту <String, Integer>
, но мне действительно нужно Double
.
Возможно не удалось решение # 1
Это конечно, не работает, потому что hibernate не знает, какие у меня параметры для встроенного объекта.
@Entity
public class MyEntity {
@Embedded
private MyEmbedded<Long, Double> embeddedMap = new MyEmbedded<>(Long.class, Double.class);
}
@Embeddable
public class MyEmbedded<K, V> {
@NotNull
private Class<K> keyClass;
@NotNull
private Class<V> valClass;
protected MyEmbedded() {
}
public MyEmbedded(Class<K> keyClass, Class<V> valClass) {
this.keyClass = keyClass;
this.valClass = valClass;
}
// [...]
@PostLoad
private void loadFromJson() {
map.clear();
if (mapAsJson != null)
// NOTICE THIS DIFFERENT LINE
map.putAll(JsonUtil.fromString(mapAsJson, HashMap.class, keyClass, valClass));
}
}
Возможное решение # 2
@Embeddable
public class MyEmbedded<K, V> {
@NotNull
private Class<K> keyClass;
@NotNull
private Class<V> valClass;
// [...]
// Call this in the entity once, on the embedded. Maybe on @PostLoad?
public MyEmbedded<K, V> init(Class<K> keyClass, Class<V> valClass) {
this.keyClass = keyClass;
this.valClass = valClass;
}
}