Hibernate 6迁移问题:自定义CompositeUserType类型转换异常
Hibernate 6迁移:CompositeUserType导致String转Enum类型转换异常解决
问题核心
从Hibernate 5迁移到6后,替换UserType为CompositeUserType实现AlertData的自定义映射时,出现ClassCastException: java.lang.String cannot be cast to java.lang.Enum,本质是type字段的类型映射逻辑错误:数据库存储的是String,但代码中尝试将其强制转换为Enum类型,或Hibernate的类型配置不匹配。
修复步骤
1. 确认AlertData的type字段定义
确保AlertData中type字段的类型与映射逻辑一致:
public class AlertData implements Serializable { private AlertType type; // AlertType为自定义枚举类 private String data; // 存储JSON字符串 // getter/setter方法 }
2. 修正CompositeUserType的关键方法实现
重点确保getPropertyTypes()、nullSafeGet()、nullSafeSet()三个方法的逻辑正确,让Hibernate明确type字段对应数据库的String类型:
public class AlertDataType implements CompositeUserType<AlertData> { // 返回属性对应的Hibernate类型:type和data都对应String类型 @Override public Type[] getPropertyTypes() { return new Type[] { StringType.INSTANCE, StringType.INSTANCE }; } // 获取组件属性值:将Enum转为String用于存储 @Override public Object getPropertyValue(AlertData component, int property) { if (property == 0) { return component.getType() != null ? component.getType().name() : null; } else { return component.getData(); } } // 将属性写入数据库:把Enum转为String存入 @Override public void nullSafeSet(PreparedStatement st, AlertData value, int index, SharedSessionContractImplementor session) throws SQLException { if (value == null) { st.setNull(index, Types.VARCHAR); st.setNull(index + 1, Types.VARCHAR); return; } st.setString(index, value.getType().name()); st.setString(index + 1, value.getData()); } // 从数据库读取数据:将String转为Enum实例 @Override public AlertData nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws SQLException { String typeStr = rs.getString(names[0]); String dataStr = rs.getString(names[1]); if (rs.wasNull()) { return null; } AlertData alertData = new AlertData(); alertData.setType(AlertType.valueOf(typeStr)); alertData.setData(dataStr); return alertData; } // 实现其他必要方法(deepCopy、isMutable、assemble、disassemble等) }
3. 修正实体类的映射配置
使用@Embedded时需搭配@Type指定自定义的CompositeUserType,确保映射逻辑生效:
@Entity public class YourEntity { @Type(value = AlertDataType.class) @Embedded protected AlertData data; // 其他实体字段... }
4. 排查数据库表结构
确认数据库中存储type的字段为VARCHAR类型;如果之前Hibernate 5中存储的是Enum的ordinal数值,需先做数据迁移,将数值转为对应Enum的name字符串。
异常原因总结
出现类型转换异常通常是以下情况之一:
CompositeUserType的getPropertyTypes()错误地将type字段指定为EnumType,导致Hibernate尝试把数据库的String转成EnumnullSafeGet()方法中直接将ResultSet读取的String强制转换为Enum,未通过Enum.valueOf()做合法转换- 实体类映射未正确指定自定义类型,导致Hibernate使用默认的Enum映射逻辑
内容的提问来源于stack exchange,提问作者Ken
相关产品推荐
相关产品推荐

