【问题标题】:Parameterized constructor on hibernate entity休眠实体上的参数化构造函数
【发布时间】: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) 基本上是在猜测类型。它目前返回&lt;String, Integer&gt; 的地图,但我实际上需要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 解析为实际的地图?那么该方法需要是通用的。我将在下面发布完整的答案。

标签: java json hibernate


【解决方案1】:

由于您进一步指定JsonUtil 是一个自己的类,我建议JsonUtil.fromString 使用以下签名:

public static <K, V> Map<K, V> fromString(String json, Class<K> keyClass,
        Class<V> valueClass, @SuppressWarnings("rawtypes") Class<? extends Map> mapClass) {
// ...

这样,您返回的地图将被推断为正确的类型,并且您可以使用您的“我想要的”变体。您可以有不同的命名签名,用于委托给该方法的其他不太庞大的访问:

public static <V> Map<V> fromStringLongKey(String json,
        Class<V> valueClass, @SuppressWarnings("rawtypes") Class<? extends Map> mapClass) {
    return fromString(json, Long.class, valueClass, mapClass);
}
//...

【讨论】:

  • 感谢您的回答,但我的问题更像是一个休眠问题。我需要一种优雅的方式来告诉我的Embedded 对象什么是键和值类。只有这样我才能采纳你的建议。
猜你喜欢
  • 2014-10-16
  • 1970-01-01
  • 1970-01-01
  • 2015-12-15
  • 2018-06-05
  • 1970-01-01
  • 2017-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多