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

Hibernate 6中@TypeDefs替代方案咨询:带参数自定义类型实现

Hibernate 6 中带参数自定义类型的等价实现方案

在Hibernate 6中,@TypeDef和@TypeDefs注解已被移除,针对需要传递参数的自定义类型(如实现DynamicParameterizedType的MonetaryAmountUserType),可以通过以下几种方案替代原Hibernate 5的实现:

方案一:使用@BasicType + @Basic(parameters)

这种方式直接在自定义类型上标记基础类型注册,然后在实体属性上指定参数,是最贴近原注解用法的替代方案:

  1. 首先在自定义类型类上添加@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");
    }
}
  1. 在实体类的属性上,通过@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,可以通过自定义注解传递参数,再在转换器中读取参数值:

  1. 创建自定义参数注解:
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();
}
  1. 修改转换器实现,同时实现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逻辑...
}
  1. 在实体属性上同时使用@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:47:10