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

Hibernate Envers结合PostgreSQL枚举映射部署报错求助

解决Hibernate Envers搭配@Enumerated(EnumType.STRING)在Glassfish 5.0的ClassCastException问题

我之前在Glassfish环境下搭配Hibernate Envers处理枚举类型时,碰到过一模一样的报错,这本质是Hibernate Envers 5.2.x版本在处理字符串枚举映射时的兼容问题,结合Glassfish的类加载机制就触发了类型转换异常。给你几个可行的解决思路:

1. 升级Hibernate版本(最推荐)

这个问题在Hibernate 5.3及以上版本已经被官方修复了。建议你把Hibernate Core和Envers都升级到5.3.x的稳定版本(比如5.3.20.Final),同时搭配兼容的Hibernate Validator版本(比如6.1.x系列),确保所有Hibernate相关组件版本统一,避免版本冲突。

2. 自定义枚举类型(无法升级版本时的替代方案)

如果暂时不能升级Hibernate版本,可以自己实现一个自定义类型来处理枚举的字符串映射,让Envers能正确识别为CustomType:

实现自定义UserType

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.StringType;
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.Objects;

public class EnumStringUserType<T extends Enum<T>> implements UserType {
    private Class<T> enumClass;

    // 初始化枚举类,可通过注解参数传入
    public EnumStringUserType(Class<T> enumClass) {
        this.enumClass = enumClass;
    }

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

    @Override
    public Class<T> returnedClass() {
        return enumClass;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return Objects.equals(x, y);
    }

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

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
        String value = StringType.INSTANCE.nullSafeGet(rs, names[0], session, owner);
        return value == null ? null : Enum.valueOf(enumClass, value);
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.VARCHAR);
        } else {
            StringType.INSTANCE.nullSafeSet(st, ((Enum<?>) value).name(), index, session);
        }
    }

    @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;
    }
}

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

import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;

@Entity
@Audited
// 定义自定义类型,指定枚举类
@TypeDef(name = "yourEnumType", typeClass = EnumStringUserType.class, parameters = {
        @org.hibernate.annotations.Parameter(name = "enumClass", value = "com.yourpackage.YourEnum")
})
public class YourEntity {
    @Type(type = "yourEnumType")
    private YourEnum yourEnum;

    // 其他字段和方法...
}

3. 调整Glassfish类加载优先级

有时候Glassfish容器自带的Hibernate库和你应用打包的版本冲突,导致类加载异常。可以在glassfish-web.xml(Web应用)或者glassfish-application.xml(EAR应用)中配置类加载策略,让应用优先使用自身打包的库:

<glassfish-web-app>
    <class-loader delegate="false"/>
</glassfish-web-app>

注意:修改类加载策略后,要确保应用打包的所有依赖都完整,避免容器提供的类缺失问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:23:15