【发布时间】:2020-05-08 10:29:48
【问题描述】:
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 个像这样的其他字段,那将是很多重复的代码。当然,这是一个非常具体的例子,但它可以扩展到地图以外的其他对象。
为什么它不起作用
这个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;
}
}
【问题讨论】:
-
JsonUtil的确切类别是什么? - 您正在使用哪个库。如果使用正确的地图 (Map),您的变体“我想要的”应该可以工作,但是,您必须验证所有条目实际上都是 Doubles。 -
@TreffnonX
JsonUtil只是委托给com.fasterxml.jackson.databind.ObjectMapper,上面只有一些检查和异常处理。验证目前不会成为问题,因为我在编译时就知道我想要输入和输出什么。这有意义吗? -
所以您使用自己的
JsonUtil类将mapAsJson解析为实际的地图?那么该方法需要是通用的。我将在下面发布完整的答案。