Search code examples
spring-data-r2dbc

What is the alternative to javax.persistence.AttributeConverter in r2dbc


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.


Solution

  • 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()
    
        )
      }
    }