[英]Parameterized constructor on hibernate entity
TL;DR TL;博士
Is there any way to cleanly pass some arguments to a hibernate-instantiated object post-load?有什么方法可以干净地将一些 arguments 传递给休眠实例化的 object 后加载?
What I have我有的
@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
}
What I want我想要的是
@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));
}
}
Why do I want it为什么我想要它
Just to nicely encapsulate the hydration to/from this working map object.只是为了很好地封装这个工作 map object 的水合作用。 If I were to have 2 more other fields like this, it would be a lot of repeated code.
如果我还有 2 个像这样的其他字段,那将是很多重复的代码。 This is a very specific example, of course, but it could be extended to other objects other than map.
当然,这是一个非常具体的示例,但它可以扩展到 map 以外的其他对象。
Why it doesn't work为什么它不起作用
This JsonUtil.fromString(mapAsJson, HashMap.class)
is basically guessing the types.这个
JsonUtil.fromString(mapAsJson, HashMap.class)
基本上是在猜测类型。 It currently returns a map of <String, Integer>
, but I'm actually needing Double
.它目前返回
<String, Integer>
的 map ,但我实际上需要Double
。
Possible failed solution #1可能失败的解决方案 #1
This of course does not work because hibernate has no idea what my parameters for the embedded object are.这当然不起作用,因为 hibernate 不知道我的嵌入式 object 参数是什么。
@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));
}
}
Possible solution #2可能的解决方案#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;
}
}
Due to you further specifying that JsonUtil
is an own class, I would suggest the following signature for JsonUtil.fromString
:由于您进一步指定
JsonUtil
是自己的 class,我建议为JsonUtil.fromString
使用以下签名:
public static <K, V> Map<K, V> fromString(String json, Class<K> keyClass,
Class<V> valueClass, @SuppressWarnings("rawtypes") Class<? extends Map> mapClass) {
// ...
This way, your returned map will be inferred with the correct types, and you can use your 'What I want'-variant.这样,您返回的 map 将被推断为正确的类型,并且您可以使用您的“我想要的”变体。 You can have differnent named signatures for other, less bulky access, that delegates to that method:
对于委托给该方法的其他不太庞大的访问,您可以使用不同的命名签名:
public static <V> Map<V> fromStringLongKey(String json,
Class<V> valueClass, @SuppressWarnings("rawtypes") Class<? extends Map> mapClass) {
return fromString(json, Long.class, valueClass, mapClass);
}
//...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.