一尘不染

JPA(EclipseLink)定制类型是否可能?

json

我尤其对使用PostgreSQLs json类型感兴趣。

问题的核心似乎是Eclipselink中没有要json 类型的内部映射。因此,使用朴素的方法:

@Column(name = "json", columnDefinition = "json")
public String getJson() {
    return json;
}

…并尝试插入对象,但出现异常:

Internal Exception: org.postgresql.util.PSQLException: ERROR: column "json" is of type json but expression is of type character varying

我猜很公平。

浏览EclipseLink文档,似乎适用的自定义项(转换映射,本机查询,转换器)依赖于由受支持的映射(数字,日期,字符串等)组成的数据,因此这使使用它变得很尴尬供应商特定类型。

令人沮丧的主要原因是jsonposgresql 中的类型表示为与text / varchar相同,并且我相信(目前(但不是永远))只是该类型的别名-
因此,驱动程序具有足够的能力来传输此类型,这只是我的验证规则。

在解决方案方面,我不介意失去可移植性(就数据库不可知和使用特定于供应商的类型而言),而只是想要一种允许我将json类型用作常规JPA实体上的属性并保留所有它习惯的其他行为(模式生成,合并,持久化,事务代码


阅读 286

收藏
2020-07-27

共1个答案

一尘不染

遍历SO的过程中,我发现了许多类似这样的问题,这些问题涉及映射到Postgres的JSON或XML类型。似乎没有人遇到过从自定义Postgres类型读取的问题,因此这里是使用纯JPA类型转换机制进行读取和写入的解决方案。

Postgres
JDBC驱动程序将未知类型(到Java)的所有属性映射到org.postgresql.util.PGobject对象,因此足以为该类型创建转换器。这是实体示例:

@Entity
public class Course extends AbstractEntity {
    @Column(name = "course_mapped", columnDefinition = "json")
    @Convert(converter = CourseMappedConverter.class)
    private CourseMapped courseMapped;  // have no idea why would you use String json instead of the object to map

    // getters and setters
}

这里是转换器的示例:

@Converter
public class CourseMappedConverter implements AttributeConverter<CourseMapped, PGobject> {
    @Override
    public PGobject convertToDatabaseColumn(CourseMapped courseMapped) {
        try {
            PGobject po = new PGobject();
            // here we tell Postgres to use JSON as type to treat our json
            po.setType("json");
            // this is Jackson already added as dependency to project, it could be any JSON marshaller
            po.setValue((new ObjectMapper()).writeValueAsString(courseMapped));
            return po;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public CourseMapped convertToEntityAttribute(PGobject po) {
        try {
            return (new ObjectMapper()).readValue(po.getValue(),CourseMapped.class);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

如果您确实需要在实体中坚持使用String JSON表示形式,则可以为String类型创建类似这样的转换器

implements AttributeConverter<String, PGobject>

这是一个非常肮脏的(尽管有效的)概念证明,它还使用伪造的对象序列化来告诉JPA如果对象已更改,

https://github.com/sasa7812/psql-cache-evict-
POC

2020-07-27