I need to store YearMonth
in postgres. According to this SO answer the best postgres type is date
.
Given that we use kotlin + spring-data-r2dbc, how should we implement the mapping?
With an AttributeConverter
I would implement it like this:
import java.time.LocalDate
import java.time.YearMonth
import javax.persistence.AttributeConverter
class YearMonthIntegerAttributeConverter : AttributeConverter<YearMonth?, Int?> {
fun convertToDatabaseColumn(
attribute: YearMonth?
): LocalDate? {
return attribute?.atDay(1)
}
fun convertToEntityAttribute(
date: LocalDate?
): YearMonth? {
if (date == null) {
return null
}
return YearMonth.of(date.year, date.month)
}
}
But using a AttributeConverter
is not possible because javax.persistence
is not available in this stack.
Turns out reading the docs again solves it.
The alternatives are
import org.springframework.core.convert.converter.Converter
import org.springframework.data.convert.ReadingConverter
import org.springframework.data.convert.WritingConverter
and the above example can be implemented like this:
@WritingConverter
class YearMonthToDateConverter : Converter<YearMonth, LocalDate> {
override fun convert(source: YearMonth): LocalDate {
return source?.atDay(1)
}
}
@ReadingConverter
class DateToYearMonthConverter : Converter<LocalDate, YearMonth> {
override fun convert(source: LocalDate): YearMonth {
return YearMonth.of(source.year, source.month)
}
}
This requires to register the converters with the r2dbc configuration AbstractR2dbcConfiguration
.
@Configuration
class R2dbcConfig(
private val connectionFactory: ConnectionFactory,
) : AbstractR2dbcConfiguration() {
override fun connectionFactory() = connectionFactory
override fun getCustomConverters(): List<Any> {
return listOf<Converter<out Any, out Any>>(
YearMonthToDateConverter(),
DateToYearMonthConverter()
)
}
}