You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Corda 3.0是否支持持久化java.time系列数据类型?

关于Corda 3.0中java.time.Year持久化的问题解答

没错,Corda 3.0(搭配其内置的Hibernate 5.2.6和JPA 2.1)确实不默认支持java.time.Year类型的持久化。原因很直接:

  • JPA 2.1规范本身并未包含对Year这个类型的映射定义
  • Hibernate 5.2.x虽然对java.time下的常用类型(比如LocalDate、LocalDateTime)提供了内置支持,但Year不在默认支持的列表中,所以当FinalityFlow提交状态时,Hibernate无法找到对应的类型映射,就会抛出错误。

下面给你几个可行的解决方案:

方案1:自定义Hibernate用户类型

你可以实现Hibernate的UserType接口,手动定义Year与数据库字段的转换逻辑,比如将Year转为数据库中的INTEGER类型存储。

自定义类型示例代码

public class YearUserType implements UserType {

    @Override
    public int[] sqlTypes() {
        return new int[]{Types.INTEGER};
    }

    @Override
    public Class returnedClass() {
        return Year.class;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (x == y) return true;
        if (x == null || y == null) return false;
        return x.equals(y);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
        Integer yearValue = rs.getInt(names[0]);
        return rs.wasNull() ? null : Year.of(yearValue);
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.INTEGER);
        } else {
            Year year = (Year) value;
            st.setInt(index, year.getValue());
        }
    }

    // 其余方法默认实现
    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }
}

在实体类中使用自定义类型

修改你的实体类,给issuedYear字段加上@Type注解指定自定义类型:

@Entity
@Table(name = "custom_states")
class CustomEntity(
    @Column(name = "issued_date")
    var issuedDate: LocalDate? = null,
    
    @Column(name = "issued_year")
    @Type(type = "com.your.package.YearUserType") // 替换成你的自定义类包路径
    var issuedYear: Year? = null
)

方案2:改用Integer存储年份(最简单的替代方案)

如果不想自定义类型,可以直接用Integer来存储年份值,在业务逻辑层再转换为Year类型:

修改后的实体类

@Entity
@Table(name = "custom_states")
class CustomEntity(
    @Column(name = "issued_date")
    var issuedDate: LocalDate? = null,
    
    @Column(name = "issued_year")
    var issuedYear: Int? = null // 用Int存储年份
) {
    // 可选:添加辅助方法,方便获取Year类型
    fun getIssuedYearAsYear(): Year? {
        return issuedYear?.let { Year.of(it) }
    }
}

在业务代码中,设置年份时调用year.getValue()获取整数值;读取时用辅助方法转回Year即可。

方案3:用LocalDate间接存储年份

另一种简单的方式是用LocalDate存储年份的第一天(比如Year.of(2024).atDay(1)),利用Hibernate对LocalDate的内置支持,读取时再提取年份:

实体类示例

@Entity
@Table(name = "custom_states")
class CustomEntity(
    @Column(name = "issued_date")
    var issuedDate: LocalDate? = null,
    
    @Column(name = "issued_year_date")
    var issuedYearDate: LocalDate? = null // 存储年份的第一天
) {
    fun getIssuedYear(): Year? {
        return issuedYearDate?.let { Year.from(it) }
    }

    fun setIssuedYear(year: Year?) {
        issuedYearDate = year?.atDay(1)
    }
}

这种方式不需要额外的自定义类型,缺点是数据库字段会存储完整的日期,但对于只需要年份的场景来说也能满足需求。

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:30:41