JPA实现自定义类型(一)

我们知道,Hibernate是一个JPA的默认实现,因此,在本文中,我们用hibernate来实现一个自定义类型。

自定义类型有多种情况,比如:

基本类型——基本 Java 类型的映射 

可嵌入——复合 java 类型/POJO 的映射 

集合——映射基本和复合 java 类型的集合

先来实现一种自定义的基本类型,具体的用例就是有一个基本类型LocalDate,我们希望将这个本地日期字段对应到一个数据库的varchar。看看具体的代码:

首先创建一个LocalDateStringType

public class LocalDateStringType extends AbstractSingleColumnStandardBasicType<LocalDate> {

    public static final LocalDateStringType INSTANCE = new LocalDateStringType();

    public LocalDateStringType() {
        super(VarcharTypeDescriptor.INSTANCE, LocalDateStringJavaDescriptor.INSTANCE);
    }

    @Override
    public String getName() {
        return "LocalDateString";
    }

    @Override
    public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
        return super.resolve(value, session, owner, overridingEager);
    }

}

这里需要注意的是,我们继承的AbstractSingleColumnStandardBasicType类需要在构造函数中调用一下,而调用的参数就是LocalDate类型和Varchar类型的转化描述类。

其次我们需要自己实现转换类:LocalDateStringJavaDescriptor

public class LocalDateStringJavaDescriptor extends AbstractTypeDescriptor<LocalDate> {

    public static final LocalDateStringJavaDescriptor INSTANCE =
            new LocalDateStringJavaDescriptor();

    public LocalDateStringJavaDescriptor() {
        super(LocalDate.class, ImmutableMutabilityPlan.INSTANCE);
    }

    @Override
    public LocalDate fromString(String s) {
        return null;
    }

    @Override
    public <X> X unwrap(LocalDate localDate, Class<X> aClass, WrapperOptions wrapperOptions) {
        if (localDate == null)
            return null;

        if (String.class.isAssignableFrom(aClass))
            return (X) LocalDateType.FORMATTER.format(localDate);

        throw unknownUnwrap(aClass);
    }

    @Override
    public <X> LocalDate wrap(X value, WrapperOptions wrapperOptions) {
        if (value == null)
            return null;

        if(String.class.isInstance(value))
            return LocalDate.from(LocalDateType.FORMATTER.parse((CharSequence) value));

        throw unknownWrap(value.getClass());
    }
}

这里需要实现两个关键的方法unwrapwrap实际上就是将LocalDate转化为String,以及将String转化为LocalDate。同时注意构造函数需要将处理的类型(LocalDate)转入进去。

最后,我们用一个例子来测试一下:

public class CustomTypeTest extends AbstractTest {
    @Override
    protected Class[] entities() {
        return new Class[]{OfficeEmployee.class};
    }

    @Test
    public void testCustomType() {
        doInJPA(entityManager -> {
            LocalDate date = LocalDate.now();
            OfficeEmployee officeEmployee = new OfficeEmployee(date);
            entityManager.persist(officeEmployee);
        });
    }
}

@Entity
class OfficeEmployee  {
    @Id
    @GeneratedValue( strategy = GenerationType.AUTO)
    private Long id;

    @Column
    @Type(type = "com.jpa.demo.custom.type.LocalDateStringType")
    private LocalDate dateOfJoining;

    public OfficeEmployee(){

    }

    public OfficeEmployee(LocalDate dateOfJoining){
        this.dateOfJoining = dateOfJoining;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public LocalDate getDateOfJoining() {
        return dateOfJoining;
    }

    public void setDateOfJoining(LocalDate dateOfJoining) {
        this.dateOfJoining = dateOfJoining;
    }

    @Override
    public String toString() {
        return "OfficeEmployee{" +
                "id=" + id +
                ", dateOfJoining=" + dateOfJoining +
                '}';
    }
}

执行后可以看到LocalDate被转化为String存储到数据库啦。

欢迎大家多多交流。

版权声明:著作权归作者所有。

thumb_up 0 | star_outline 0 | textsms 0