我们知道,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());
}
}
这里需要实现两个关键的方法unwrap
和wrap
实际上就是将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存储到数据库啦。
欢迎大家多多交流。