이번포스팅에선 jackson 라이브러리에서 제공하는 @JsonCreator를 사용하는 방법에 대해 알아보려고 한다.
@JsonCreator란?
json을 class로 바꿀 때 사용하는데 생성할 class의 기본 생성자를 사용하는 게 아니라 다른 생성자나 팩토리 함수를 통해서 class를 만들고 싶을 때 사용한다.
@JsonCreator 사용법
class + @JsonCreator
- 다른 생성자
constructor 위에 @JsonCreator를 붙이고 생성자 파라미터에 @JsonProperty("필드명")을 반드시 붙여줘야 한다.
@JsonProperty를 붙이는 이유는 정확하게 모르겠지만 사용법에 붙이라고 나와있어서 붙였다.
class Member(
val id: Long,
val name: String
) {
@JsonCreator
constructor(
@JsonProperty("id") id: String,
@JsonProperty("name") name: String
) : this(
id = id.toLong(),
name = name
)
}
- 팩토리 함수
companion object에 선언해줘야 한다.
함수에 @JsonProperty를 붙이고 @JvmStatic을 반드시 붙여줘야 한다.
@JvmStatic을 붙이는 이유는 Jackson이 @JsonCreator 사용할 때 자바의 static class를 사용하는데 companion object를 사용하면 Companion Class 안에 함수가 만들어지기만 하고 별도로 static class가 생성되지 않기 때문이다.
다른 생성자를 이용하는 방법과 동일하게 생성자 파라미터에 @JsonProperty("필드명")을 반드시 붙여줘야 한다.
class Member(
val id: Long,
val name: String
) {
companion object {
@JsonCreator
@JvmStatic
fun from(
@JsonProperty("id") id: String,
@JsonProperty("name") name: String
) = Member(
id = id.toLong(),
name = name
)
}
}
- 테스트 코드
위 2가지 방법을 테스트할 때 사용한 코드다.
class MemberTest {
@Test
fun testJsonCreator() {
val objectMapper = ObjectMapper().registerKotlinModule()
val json = """
{
"id": "1",
"name": "노력남자"
}
""".trimIndent()
assertEquals(1, objectMapper.readValue<Member>(json).id)
}
}
enum + @JsonCreator
@JsonCreator를 붙이는 방법은 위에 팩토리 함수에서 알아본 거랑 동일하다.
다른 점이 있다면 아래 코드처럼 enum을 찾는 로직( = values().first { it.code == code.toInt() } )을 넣어줘야 한다.
class User(
val userType: UserType
) {
enum class UserType(
val code: Int
) {
NORMAL(0),
ADMIN(1);
companion object {
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
@JvmStatic
fun from(
code: String
) = values().first { it.code == code.toInt() }
}
}
}
위에 코드보면 @JsonCreator에 mode 설정을 해줬는데 생성자에 있는 파라미터명과 동일한 경우 붙여줘야 한다.
안 붙이면 에러가 발생한다. 저거 찾느라 고생했다. 그냥 변수명을 다르게 줄 걸 그랬나...
- mode 설명
- 생성자에 있는 모든 매개 변수가 JSON 속성 이름과 일치하면 Jackson은 JsonCreator.Mode.PROPERTIES 모드로 간주합니다. 이 모드에서는 생성자의 매개 변수와 JSON 속성 이름이 일치해야 합니다.
- 생성자에 있는 매개 변수 중 하나 이상의 이름이 @JsonProperty 어노테이션을 통해 명시적으로 지정되었다면 Jackson은 JsonCreator.Mode.PROPERTIES 모드로 간주합니다.
- 그렇지 않은 경우, 생성자에 있는 매개 변수의 순서와 JSON 데이터의 순서가 일치해야 하며, Jackson은 JsonCreator.Mode.DELEGATING 모드로 간주합니다.
- 테스트 코드
class UserTest {
@Test
fun testJsonCreator() {
val objectMapper = ObjectMapper().registerKotlinModule()
val json = """
{
"userType": "0"
}
""".trimIndent()
assertEquals(User.UserType.NORMAL, objectMapper.readValue<User>(json).userType)
}
}
댓글