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

如何在Hibernate-Mapping XML(HBM 4.3)中使用JPA AttributeConverter?

解决方案:Hibernate 4.3.x下hbm.xml中使用JPA AttributeConverter

这个问题我之前也碰到过,Hibernate 4.3.x对JPA AttributeConverter的hbm.xml支持确实有局限性——你直接在<property>的type属性里指定Converter类是行不通的,因为Hibernate的type字段需要的是Hibernate自身的Type接口实现(比如UserType或BasicType),而不是JPA规范的AttributeConverter类。

结合你的场景(Avro生成的实体无法加注解),下面是可行的解决步骤:

1. 用自定义UserType封装AttributeConverter逻辑

创建一个实现Hibernate UserType接口的类,把你的DateToLongConverter的转换逻辑包裹进去:

import org.hibernate.usertype.UserType;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;
import org.hibernate.engine.spi.SessionImplementor;
import dao.converter.DateToLongConverter;

public class DateToLongUserType implements UserType {

    // 实例化你的JPA转换器
    private final DateToLongConverter converter = new DateToLongConverter();

    @Override
    public int[] sqlTypes() {
        // 对应数据库中的BIGINT类型
        return new int[]{Types.BIGINT};
    }

    @Override
    public Class<?> returnedClass() {
        // 实体类中的属性类型
        return Date.class;
    }

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

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

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws SQLException {
        // 从数据库读取Long,转换为Date
        Long dbValue = rs.getLong(names[0]);
        return rs.wasNull() ? null : converter.convertToEntityAttribute(dbValue);
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws SQLException {
        // 把Date转换为Long写入数据库
        if (value == null) {
            st.setNull(index, Types.BIGINT);
            return;
        }
        Long dbValue = converter.convertToDatabaseColumn((Date) value);
        st.setLong(index, dbValue);
    }

    @Override
    public Object deepCopy(Object value) {
        // Date是不可变类型,直接返回即可
        return value;
    }

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

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

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

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

2. 修改hbm.xml映射

在<property>标签中,将type属性指定为你刚才创建的UserType的全类名,而不是原来的AttributeConverter类:

<property name="aColumn" column="A_COLUMN" type="dao.usertype.DateToLongUserType"/>

3. 移除不必要的配置

因为我们已经通过UserType封装了转换逻辑,你可以移除persistence.xml中对DateToLongConverter的注册(保留也不会有冲突,但没必要)。

为什么原来的方法会报错?

Hibernate 4.3.x虽然支持JPA 2.1的AttributeConverter,但它的hbm.xml解析器并没有实现直接引用AttributeConverter类的逻辑——type字段只能识别Hibernate原生的Type实现,或者你自定义的UserType/BasicType。而AttributeConverter通常是通过实体类上的@Convert注解来关联的,但你的实体是Avro生成的无法添加注解,所以必须用UserType来做中间层。

如果未来有机会升级到Hibernate 5.x+,你会发现它对hbm.xml的Converter支持更友好,可以直接通过<property>的converter属性指定Converter类,但在4.3.x版本中,上述方法是最稳妥的解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:00:42