Spring

[Spring + Kotlin] class, enum에 @JsonCreator 사용하는 방법

노력남자 2023. 11. 9. 23:50
반응형

이번포스팅에선 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 설명

 

  1. 생성자에 있는 모든 매개 변수가 JSON 속성 이름과 일치하면 Jackson은 JsonCreator.Mode.PROPERTIES 모드로 간주합니다. 이 모드에서는 생성자의 매개 변수와 JSON 속성 이름이 일치해야 합니다.
  2. 생성자에 있는 매개 변수 중 하나 이상의 이름이 @JsonProperty 어노테이션을 통해 명시적으로 지정되었다면 Jackson은 JsonCreator.Mode.PROPERTIES 모드로 간주합니다.
  3. 그렇지 않은 경우, 생성자에 있는 매개 변수의 순서와 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)
    }
}
반응형