Using JPA AttributeConverter
For YearMonth
, you can create the following YearMonthDateAttributeConverter
like this:
public class YearMonthDateAttributeConverter
implements AttributeConverter<YearMonth, java.sql.Date> {
@Override
public java.sql.Date convertToDatabaseColumn(
YearMonth attribute) {
return java.sql.Date.valueOf(attribute.atDay(1));
}
@Override
public YearMonth convertToEntityAttribute(
java.sql.Date dbData) {
return YearMonth
.from(Instant.ofEpochMilli(dbData.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate());
}
}
And, use @Convert
on the YearMonth
JPA entity property:
@Column(name = "published_on", columnDefinition = "date")
@Convert(converter = YearMonthDateAttributeConverter.class)
private YearMonth publishedOn;
Using a Hibernate custom Type
You can create a custom Hibernate Type by extending the AbstractSingleColumnStandardBasicType
:
public class YearMonthDateType
extends AbstractSingleColumnStandardBasicType<YearMonth> {
public static final YearMonthDateType INSTANCE =
new YearMonthDateType();
public YearMonthDateType() {
super(
DateTypeDescriptor.INSTANCE,
YearMonthTypeDescriptor.INSTANCE
);
}
public String getName() {
return "yearmonth-date";
}
@Override
protected boolean registerUnderJavaType() {
return true;
}
}
And define the YearMonthTypeDescriptor
as follows:
public class YearMonthTypeDescriptor
extends AbstractTypeDescriptor<YearMonth> {
public static final YearMonthTypeDescriptor INSTANCE =
new YearMonthTypeDescriptor();
public YearMonthTypeDescriptor() {
super(YearMonth.class);
}
@Override
public boolean areEqual(
YearMonth one,
YearMonth another) {
return Objects.equals(one, another);
}
@Override
public String toString(
YearMonth value) {
return value.toString();
}
@Override
public YearMonth fromString(
String string) {
return YearMonth.parse(string);
}
@SuppressWarnings({"unchecked"})
@Override
public <X> X unwrap(
YearMonth value,
Class<X> type,
WrapperOptions options) {
if (value == null) {
return null;
}
if (String.class.isAssignableFrom(type)) {
return (X) toString(value);
}
if (Date.class.isAssignableFrom(type)) {
return (X) java.sql.Date.valueOf(value.atDay(1));
}
throw unknownUnwrap(type);
}
@Override
public <X> YearMonth wrap(
X value,
WrapperOptions options) {
if (value == null) {
return null;
}
if (value instanceof String) {
return fromString((String) value);
}
if (value instanceof Date) {
Date date = (Date) value;
return YearMonth
.from(Instant.ofEpochMilli(date.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate());
}
throw unknownWrap(value.getClass());
}
}
You don't need to write this type by yourself, you can use the Hibernate Types and just declare the Maven dependency like this:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
That's it!