【问题标题】:How to emulate Attribute Converter in JPA <= 2.0?如何在 JPA <= 2.0 中模拟属性转换器?
【发布时间】:2025-12-25 00:50:07
【问题描述】:

JPA 2.1 引入了一个不错的新功能 Attribute Converter - 请参阅文章,例如这里:http://www.thoughts-on-java.org/jpa-21-how-to-implement-type-converter/

它允许您拥有某种类型的属性并将其作为其他内容存储在数据库列中。例如。您有一个字段颜色为java.awt.Color 类型的实体,但您希望将其作为String 存储在数据库中,例如REDWHITE

@Entity
class Tag {
    String name;
    java.awt.Color color; // I want it to be stored as a different type
}

有没有办法在 JPA 中获得类似的结果?我想为 not enum 的类型执行此操作。

我们不区分业务领域层和@Entity 类。当然,如果它们之间存在某种映射,我可以想象许多可行的解决方案。我正在寻找的是一种解决方案,我们在业务领域层中直接使用@Entity 类本身。

【问题讨论】:

  • 在我之前工作的系统中,他们每次使用前都会序列化类和反序列化字段。
  • @user902383,你能说得更具体点吗?我直接使用@Entity 类作为域类。如果域类与@Entity 类不同,我可以想象一百万种解决方案。
  • 依赖于实现。有些人早在那时就有“类型转换器”。你没有提到你的实现是什么
  • @NeilStockton,我更喜欢与实现无关的解决方案。

标签: java jakarta-ee jpa jpa-2.0


【解决方案1】:

我的建议是创建此列@Transient 并添加另一个@Column,这将是awt.Color 的字符串值,使用getter 和setter 作为转换器。

你的班级会是这样的:

@Transient
java.awt.Color color;
@Column
String colorField;

每次你使用你的 Color 使用 setter,这个 setter 会解码颜色并将它添加到 colorField 字段中。

public setColor(java.awt.Color color){
  this.colorField = color.toString();
  this.color = color;
}

【讨论】:

  • 只是一个小注释,你不需要瞬态字段color 只需创建瞬态 setter 和 getter 即可自动进行转换
  • 希望 TomEE 遇到问题的人在谷歌搜索中能找到答案。
【解决方案2】:

正如我在评论中提到的,在我正在工作的系统中,自定义非实体类被序列化为字节数组并作为 blob 放入 db,并在使用前反序列化。

字段被映射为:

 @Column(name = "data")
 private byte[] data;

然后我们有两个静态方法的 util 类

public static byte[] serialize(Object object) throws IOException,
            ClassNotFoundException {
        // Serialize to a byte array
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(object);
        out.close();

        // Get the bytes of the serialized object
        byte[] buf = bos.toByteArray();
        return buf;
    }

    public static Object deserialize(byte[] data) throws IOException,
            ClassNotFoundException {
        // Deserialize from a byte array
        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(
                data));
        Object o = in.readObject();
        in.close();
        return o;
    }

现在您可以创建瞬态 getter 和 setter 并使用反序列化和反序列化在您的类之间进行转换

不确定它是推荐的解决方案,但这是直接从现有系统复制的

【讨论】:

  • 有趣的解决方案,虽然它不是我想要的——我不需要存储对象的内容,而是转换它。但是,您应该得到我的加分 :) 无论如何,它或多或少与 Koitoer 提到的相同,只是更具体。对我来说,这里的关键思想是使用 @Transient 字段进行映射。
  • 对不起,我误解了你,这完全取决于你想要存储/转换什么样的对象,也许你可以用枚举和Enumerated 注释做一些事情,或者按照 Koitoer 的建议去做。