Hibernate 6中@TypeDefs替代方案咨询:带参数自定义类型实现
Hibernate 6 中带参数自定义类型的等价实现方案
在Hibernate 6中,@TypeDef和@TypeDefs注解已被移除,针对需要传递参数的自定义类型(如实现DynamicParameterizedType的MonetaryAmountUserType),可以通过以下几种方案替代原Hibernate 5的实现:
方案一:使用@BasicType + @Basic(parameters)
这种方式直接在自定义类型上标记基础类型注册,然后在实体属性上指定参数,是最贴近原注解用法的替代方案:
- 首先在自定义类型类上添加
@BasicType注解,将其注册为Hibernate基础类型:
import org.hibernate.annotations.BasicType; @BasicType public class MonetaryAmountUserType implements DynamicParameterizedType { // 原类型实现逻辑... private String convertTo; @Override public void setParameterValues(Properties parameters) { this.convertTo = parameters.getProperty("convertTo"); } }
- 在实体类的属性上,通过
@Basic注解的parameters传递参数:
import jakarta.persistence.Basic; import org.hibernate.annotations.Parameter; public class Order { // 对应原monetary_amount_usd的用法 @Basic(parameters = @Parameter(name = "convertTo", value = "USD")) private MonetaryAmount usdAmount; // 对应原monetary_amount_eur的用法 @Basic(parameters = @Parameter(name = "convertTo", value = "EUR")) private MonetaryAmount eurAmount; }
方案二:通过MetadataBuilder预注册命名类型
如果需要像原代码那样预定义带有固定参数的命名类型(如monetary_amount_usd、monetary_amount_eur),可以在Hibernate配置阶段通过MetadataBuilder手动注册:
import org.hibernate.boot.MetadataBuilder; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; // 构建Hibernate配置时注册类型 StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build(); MetadataSources sources = new MetadataSources(registry); MetadataBuilder metadataBuilder = sources.getMetadataBuilder(); // 注册带USD参数的命名类型 metadataBuilder.applyBasicType( new MonetaryAmountUserType(), "monetary_amount_usd", Map.of("convertTo", "USD") ); // 注册带EUR参数的命名类型 metadataBuilder.applyBasicType( new MonetaryAmountUserType(), "monetary_amount_eur", Map.of("convertTo", "EUR") ); // 后续构建SessionFactory...
之后在实体类中就可以直接通过@Type注解引用预定义的命名类型:
import org.hibernate.annotations.Type; public class Order { @Type(name = "monetary_amount_usd") private MonetaryAmount usdAmount; @Type(name = "monetary_amount_eur") private MonetaryAmount eurAmount; }
方案三:自定义带参数的转换器注解
如果更倾向于使用JPA标准的@Convert,可以通过自定义注解传递参数,再在转换器中读取参数值:
- 创建自定义参数注解:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MonetaryConvert { String convertTo(); }
- 修改转换器实现,同时实现
ParameterizedType并读取自定义注解的参数:
import jakarta.persistence.AttributeConverter; import org.hibernate.type.ParameterizedType; import java.lang.reflect.Field; import java.util.Properties; public class MonetaryAmountConverter implements AttributeConverter<MonetaryAmount, String>, ParameterizedType { private String convertTo; @Override public void setParameterValues(Properties parameters) { // 从参数中获取字段的自定义注解 Field field = (Field) parameters.get("field"); MonetaryConvert annotation = field.getAnnotation(MonetaryConvert.class); if (annotation != null) { this.convertTo = annotation.convertTo(); } } // 实现convertToDatabaseColumn和convertToEntityAttribute逻辑... }
- 在实体属性上同时使用
@Convert和自定义注解:
import jakarta.persistence.Convert; public class Order { @Convert(converter = MonetaryAmountConverter.class) @MonetaryConvert(convertTo = "USD") private MonetaryAmount usdAmount; @Convert(converter = MonetaryAmountConverter.class) @MonetaryConvert(convertTo = "EUR") private MonetaryAmount eurAmount; }
内容的提问来源于stack exchange,提问作者Yassir Acaf
相关产品推荐
相关产品推荐

