본문 바로가기

GAB STORY

일상 속 소소한 순간들과 개발 공부 과정에서의 다양한 경험들을 담아낸 공간입니다.
DEVELOPE

Interface-based Projection에서 ZonedDateTime Converter 사용

by 갑스토리 2023. 2. 8.

Interface-based에서 Timestamp로 선언된 컬럼을 ZonedDateTime으로 변환하여 사용하는 방법.


에러

Cannot project java.sql.Timestamp to java.time.ZonedDateTime. Target type is not an interface and no matching Converter found!
java.lang.UnsupportedOperationException: Cannot project java.sql.Timestamp to java.time.ZonedDateTime. Target type is not an interface and no matching Converter found!

CREATE TABLE `table` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `created` datetime NOT NULL COMMENT '생성일'
  PRIMARY KEY (`id`),
)


select rows : 7, '2022-12-12 11:09:13'

interface DTO {
    val id: Int
    val created: ZonedDateTime
}


@Query( value = "SELECT * FROM table", nativeQuery = true)
fun findAll() : List<DTO>



Interface-based Projection에서 ZonedDateTime으로 설정된 경우 Converter가 정상적으로 동작하지 않아 오류가 발생합니다.
springboot 2.4.0 미만의 버전에서는 DefaultConversionService.getSharedInstance()에 추가하고
2.4.0부터는 reflection으로 ProxyProjectionFactory에 Converter을 추가합니다.
datetime, timstamp 이외 숫자 형태로 생성된 컬럼도 비슷한 유형으로 대응할 수 있습니다.

@Component
class ProxyProjectionFactoryDefaultConversionServiceInitializer : InitializingBean {
    override fun afterPropertiesSet() {
        val aClass = Class.forName("org.springframework.data.projection.ProxyProjectionFactory")
        val field: Field = aClass.getDeclaredField("CONVERSION_SERVICE").apply {
            isAccessible = true
        }

        (field.get(null) as GenericConversionService).apply {
            addConverter(TimestampToZonedDateTimeConverter())
        }
    }
}

class TimestampToZonedDateTimeConverter :
    org.springframework.core.convert.converter.Converter<Timestamp, ZonedDateTime> {
    override fun convert(source: Timestamp): ZonedDateTime {
        return source.toLocalDateTime().toZonedDateTime()
    }
}


fun LocalDateTime.toZonedDateTime(){
  // 변환 로직   
}


Mysql datetime, timestamp 차이

timestamp는 세션에 설정된 timezone이 반영되며 datetime은 반영되지 않는다.

JDBC serverTimezone 속성

jdbc:mysql://mysql:3306/db?serverTimezone=UTC


JDBC url 파라미터에 serverTimezone포함되어 있다면 serverTimezone의 값으로 Timezone instance을 생성하여 connection 생성하고 파라미터가 존재하지 않는다면 Application의 Timezone으로 생성한다.




참고
https://kim-jong-hyun.tistory.com/132

JDBC url의 serverTimezone 속성에 대해 알아보기

웹 애플리케이션 개발을 하다보면 피해갈 수 없는 문제 중 하나가 바로 타임존(Timezone) 이다. 데이터베이스를 통해 받아온 날짜형식의 데이터를 원하는 Timezone에 맞춰서 보여줘야 하는데 제대로

kim-jong-hyun.tistory.com

https://studyposting.tistory.com/89

[MySQL] DATETIME, TIMEZONE

MySQL의 자료형 중 DATETIME과 TIMESTAMP는 모두 날짜와 시간 정보를 저장하는데 사용된다. 이 둘의 차이는 TIMEZONE의 반영 여부이다.​xCREATE TABLE datetest ( test_datetime DATETIME, test_timestamp TIMESTAMP);​INSERT INT

studyposting.tistory.com

'DEVELOPE' 카테고리의 다른 글

NoHandlerFoundException ControllerAdvice에서 제어하기  (0) 2023.08.10

댓글