我目前正在尝试创建一个自定义 Hibernate 类型,以将枚举列表映射到逗号分隔元素的 Varchar 中。为此,我编写了自己的 JavaType(旧 JavaTypeDescriptor)和自己的 BasicType。问题是,对于我的第二堂课,我需要一个 JavaType 的实例。
在 Hibernate 5 中,可以在需要时设置 JavaType,使用参数注释并在其中设置类型(使用
AbstractStandardBasicType#setJavaTypeDescriptor
)。在 Hibernate 6.2 版本中,该方法不再可用,并且 javaTypeDescriptor 字段(现在是 javaType)是最终字段,因此我无法执行此操作。
这是我尝试过的代码:
public class EnumListJavaType<E extends Enum<E>> extends AbstractJavaType<List<E>> {
private final Class<E> enumClass;
private static final String SEPARATOR = ",";
public EnumListJavaType(Class<E> enumClass) {
super(List.class);
this.enumClass = enumClass;
}
@Override
public <X> X unwrap(List<E> value, Class<X> type, WrapperOptions options) {
if (value == null)
return null;
return (X) toString(value);
}
@Override
public <X> List<E> wrap(X value, WrapperOptions options) {
if (value == null)
return null;
return fromString(value.toString());
}
@Override
public String toString(List<E> value) {
return (String) value.stream()
.map(Enum::name)
.collect(Collectors.joining(SEPARATOR));
}
public List<E> fromString(String string) {
if (StringUtils.isEmpty(string))
return null;
return Arrays.stream(string.split(SEPARATOR))
.map(s -> Enum.valueOf(enumClass, s))
.collect(Collectors.toList());
}
}
public class EnumListType<E extends Enum<E>> extends AbstractSingleColumnStandardBasicType<List<E>> implements DynamicParameterizedType {
/**
* Here the JavaType is not passed as we don't know yet the enum class.
*/
public EnumListType() {
super(VarcharJdbcType.INSTANCE, null);
@Override
public String getName() {
return "enum_list";
}
@Override
public String[] getRegistrationKeys() {
return new String[] { getName(), "EnumList", EnumSet.class.getName() };
}
@Override
public void setParameterValues(Properties parameters) {
// Here I'm not able to set the JavaType anymore as there is no such method
/* String enumClassName = (String) parameters.get("enumClass");
try {
setJavaType(new EnumSetJavaType(Class.forName(enumClassName)));
}
catch (ClassNotFoundException e) {}*/
}
我现在看到的唯一方法是删除泛型并将我的 JavaType 定义为列表。但我希望有一种更干净的方法来做到这一点。
然后我考虑创建一个工厂,以便在需要时通过使用注释 @TypeDef 来创建 HavaType。类似的东西:
public class EnumListTypeFactory implements TypeDef {
@Override
public Class getTypeClass() {
return EnumListType.class;
}
@Override
public String getTypeMethod() {
return "forEnumClass";
}
public static <E extends Enum<E>> EnumListType forEnumClass(String enumClassName) {
try {
Class<E> enumClass = (Class<E>) Class.forName(enumClassName);
return new EnumListType<>(new EnumListJavaType<>(enumClass));
} catch (ClassNotFoundException e) {
throw new HibernateException("Enum class not found", e);
}
}
但是在Hibernate 6中,@TypeDef注解似乎已经被删除了。
如果您对此有任何建议,我将不胜感激!
如果你真的想要数据库中的 varchar 列,我想你只需要提供
<E extends Enum<E>> AttributeConverter<EnumSet<E>, String>
除了使用
Set
而不是 EnumSet
,我想你可以在这里获取一个实现。