hibernate - 自定义注解

1,292 阅读2分钟

背景

  • hibernate自身提供一些注解可供使用,例如:@CreationTimestamp(新增实体时,生成创建时间)、@UpdateTimestamp(新增或更新实体时,生产更新时间)等。那如果我们期望自定义时间的生成策略时,要如何实现呢?例如:新增实体时,如果某个字段有值,就用该值;如果没有,则使用某个策略生成某个值

实现

  • 功能:自定义@CreateTime,被该注解修饰的字段,如果字段有值,则使用该值;如果该字段没值,则使用当前时间
  • 具体代码:
/**
 * 被@CreateTime注解的字段的值生成器
 * ps.暂时只支持,Timestamp,java.util.Date,java.sql.Date这三种类型
 *
 */
public final class CreateTimeGenerators {
    private static final Map<Class<?>, ValueGenerator<?>> GENERATORS;

    private CreateTimeGenerators() {

    }

    static {
        GENERATORS = new HashMap<>();
        GENERATORS.put(Date.class,
                (session, owner) -> {
                    Date date = new Date();
                    Object value = ReflectionUtils.getFieldValueWithAnnotation(owner, CreateTime.class);
                    if (value != null) {
                        date = (Date) value;
                    }
                    return date;
                }
        );

        GENERATORS.put(
                java.sql.Date.class,
                (session, owner) -> {
                    java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
                    Object value = ReflectionUtils.getFieldValueWithAnnotation(owner, CreateTime.class);
                    if (value != null) {
                        date = (java.sql.Date) value;
                    }
                    return date;
                }
        );

        GENERATORS.put(
                Timestamp.class,
                (session, owner) -> {
                    Timestamp date = new Timestamp(System.currentTimeMillis());
                    Object value = ReflectionUtils.getFieldValueWithAnnotation(owner, CreateTime.class);
                    if (value != null) {
                        date = (Timestamp) value;
                    }
                    return date;
                }
        );

    }

    @SuppressWarnings("unchecked")
    public static <T> ValueGenerator<T> get(final Class<T> type) {
        final ValueGenerator<?> valueGeneratorSupplier = GENERATORS.get(
                type);
        if (Objects.isNull(valueGeneratorSupplier)) {
            throw new HibernateException(
                    "Unsupported property type [" + type.getName() + "] for @CreateTime generator annotation");
        }

        return (ValueGenerator<T>) valueGeneratorSupplier;
    }
}
/**
 * 被@CreateTime注解的字段的值生成策略:
 * 1.insert的时候触发
 * 2.如果该字段已有值,直接使用该值,否则使用当前时间
 *
 */
public class CreateTimeGeneration implements AnnotationValueGeneration<CreateTime> {
    private ValueGenerator<?> generator;

    @Override
    public void initialize(CreateTime annotation, Class<?> propertyType) {
        generator = CreateTimeGenerators.get(propertyType);
    }

    @Override
    public GenerationTiming getGenerationTiming() {
    	// 生成时机
        return GenerationTiming.INSERT;
    }

    @Override
    public ValueGenerator<?> getValueGenerator() {
        return generator;
    }

    @Override
    public boolean referenceColumnInSql() {
        return false;
    }

    @Override
    public String getDatabaseGeneratedReferencedColumnValue() {
        return null;
    }
}
/**
 * 创建时间注解,被修饰的字段,如果值存在则使用该值,否则使用当前时间
 *
 */
@ValueGenerationType(generatedBy = CreateTimeGeneration.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(FIELD)
public @interface CreateTime {
}
public class Human{
    @CreateTime
    @Column(name = "create_time")
    private Date createTime;
}

总结

  • hibernate自定义注解实现步骤:
    • 自定义一个注解。通过@ValueGenerationType(generatedBy = CreateTimeGeneration.class)的方式指定生成器
    • 实现该生成器
      • initialize方法对ValueGenerator进行初始化(并指定生成的相关逻辑)
      • getGenerationTiming方法指定生成的时机(NEVER/INSERT/ALWAYS)
    • 注解使用方式:与hibernate自带的CreationTimestamp一致,直接在Entity的字段上进行注解即可