프로젝트에서 이틀동안 고생한 내용을 정리합니다.
프로젝트는 Grails 3.3.5 기반이고, rest-api profile 을 적용하여 api service를 개발하는 중이었습니다.
각각 라이브러리에 대한 대략적인 dependency 는 아래와 같습니다.
grails:3.3.5
gorm:6.1.9.RELEASE
hibernate5:6.1.9.RELEASE
hibernate-core:5.1.13.Final
hibernate-core 는 기본적으로 프로젝트 생성시 5.1.5 버전으로 생성해 주는데, 일단 5.1 버전의 최신버전인 5.1.13으로 설정을 변경하였습니다.
위에서 Domain 객체에 LocalDate 를 사용하고, h2 같은 데이터베이스에 테스트 데이터를 확인해보면 DATE(10) 타입으로 칼럼이 생성되는 것이 아니라, VARBINARY(255) 타입으로 생성됩니다.
물론 between 이라던지 eq Criteria 는 정상적으로 실행이 됩니다만, VARBINARY 인 칼럼을 DB에서 직접 조회할 때 난감합니다.
그리고 JSON 으로 Domain 객체를 출력해야 하는데, LocalDate 타입을 변환해주는 JsonGenerator.Converter 도 없습니다.
총체적으로 난국입니다.
일단, hibernate-core 버전을 5.2.17 의 최신버전을 사용하게 되면, java8 에 포함된 java.time.* 패키지의 클래스를 정상적? 으로 사용할 수 있습니다.
하지만 grails 에서 hibernate-core 만 버전업데이트를 하는 경우 어떤 사이드이펙트가 발생할지 몰라서, 일단 hibernate-core 버전을 5.1.13 으로 유지하면서, LocalDate 을 Database Persistent, Json 변환, Decode, Encode 가 잘 처리될 수 있도록 설정하는 것이 목적이었습니다.
Grails 가 개발에 참 어려움이 많습니다. doc 가 많은 것도 아니고, 그러다고 stackoverflow 에 질의응답이 많은 것도 아니고, 국내에 나와있는 개발 서적도 없고 ㅜㅜ
하여간, 지금은 정상적으로 잘 저장되고, 잘 변환되고 하는 설정 방법을 찾았습니다.
내용은 아래와 같습니다.
compile 'org.grails.plugins:grails-java8:1.2.3'
위의 플러그인을 추가하면, java.time.* 패키지의 LocalDate, LocalTime, OffsetDateTime, ZonedDateTime 등을 사용하여 Json 입출력이 가능해 집니다. ISO8601 포맷의 입출력을 모두 지원합니다.
예를 들어 LocalDate 가 있는 Domain 객체가 하나 있다고 하면,
class Book {
String name
LocalDate wroteDate
}
만들고 post 등으로 입력, 또는 get 을 간단히 만들어서 LocalDate 타입의 정보를 출력하면, 'yyyy-MM-dd' 형식의 문자열로 출력이 되고, 동일한 형식으로 데이터를 입력받아 LocalDate 타입의 property 에 바인딩할 수도 있습니다.
그리고 hibernate 가 정상적으로 VARBINARY 가 아닌 DATE(10) 으로 LocalDate 가 저장되도록 하기 위해서는 아래의 플러그인이 필요합니다.
compile 'org.jadira.usertype:usertype.extended:5.0.0.GA'
위의 플러그인을 추가하면, java.time.* 패키지의 Database persistent 를 처리하는 클래스들이 포함되어 있습니다.
그럼 남은 설정을 진행합니다.
LocalDate 타입이 필요한 Domain 에 property 를 추가합니다. 그리고 어떻게 db 에 매핑할 것인지 정보를 적어줍니다.
class Book {
String name
LocalDate publishDate
static mapping = {
publishDate type: PersistentLocalDate
}
}
이제 위의 Domain 정보를 db 에 저장하고, 확인해보면 정상적으로 DATE(10) 형식으로 저장되어 '2018-01-01' 같은 형식으로 잘 보이게 됩니다.
최근에 프로젝트에서 TimeZone 이 포함된 시간개념을 적용하고 있는데, 어떻게 생각하면 참 간단한 것인데, 또 어떻게 생각하면 머리가 너무 아파옵니다.
예제도 문서도 별로 없는 Grails 에서 고생이 참 많습니다.
이상으로 Grails 3.3.5 에서 java.time 패키지의 LocalDate 를 사용하는 방법이었습니다.
위와 같은 방법으로 LocalTime, OffsetDateTime, ZonedDateTime 등을 모두 적용할 수 있습니다.
감사합니다.