본문 바로가기
Spring

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

by 노력남자 2023. 11. 13.
반응형

이번 포스팅에선 Jackson의 @JsonValue 사용법에 대해 알아보겠다.
 
프로젝트에서 제일 많이 사용하는 jackson 어노테이션인데 아무 생각없이 쓰다가 문득 정리하고 싶어서 정리한다.
 

@JsonValue란?

 
@JsonValue는 직렬화할 때 사용하는 어노테이션으로 클래스의 프로퍼티, getter, 인자가 없는 메소드 에 사용할 수 있으며, 최대 1개만 사용이 가능하다. (2개 이상 사용하면 "Multiple 'as-value' properties defined" 에러가 발생한다.)
 
특이한 건 enum에 사용하면 직렬화, 역직렬화 둘 다에 사용된다. 단, @JsonCreator가 있는 경우 @JsonValue는 역직렬화에 사용되지 않는다.
 

@JsonValue 사용법

 

Class + @JsonValue

 
프로퍼티, getter, 인자가 없는 메소드 이렇게 3군데에 붙일 수 있다.
 
Member에 @JsonValue를 선언 후 MemberResponse를 직렬화하는 방식으로 테스트를 진행했다.
 

class MemberResponse(
    val member: Member
)

class Member(
    val id: Long,
    val name: String
)

 

프로퍼티

 
프로퍼티 위에 @JsonValue를 선언해주면 된다.
 

class Member(
    val id: Long,
    @JsonValue
    val name: String,
)

 
Member가 직렬화될 때 @JsonValue가 선언된 name의 값을 사용한다.
 

@Test
fun testJsonValueOnProperty() {
    val objectMapper = ObjectMapper().registerKotlinModule()
    val response = MemberResponse(Member(1, "노력남자"))

    assertEquals("""{"member":"노력남자"}""".trimIndent(), objectMapper.writeValueAsString(response))
}

 

게터

 
프로퍼티 위에 @get:JsonValue를 선언해주면 된다.
 

class Member(
    val id: Long,
    @get:JsonValue
    val name: String
)

 
Member가 직렬화될 때 @JsonValue가 선언된 name의 게터를 사용한다.
 

@Test
fun testJsonValueOnGetter() {
    val objectMapper = ObjectMapper().registerKotlinModule()
    val response = MemberResponse(Member(1, "노력남자"))

    assertEquals("""{"member":"노력남자"}""".trimIndent(), objectMapper.writeValueAsString(response))
}

 

인자가 없는 메소드

 
인자가 없는 메소드에 @JsonValue를 붙여주면 된다. (인자가 있는 메소드에 @JsonValue를 붙이면 인식이 안 된다.)
 
대게 toString에 @JsonValue를 붙여서 사용한다.
 

class Member(
    val id: Long,
    val name: String
) {

    @JsonValue
    override fun toString(): String {
        return "$id-$name"
    }
}

 
Member가 직렬화될 때 @JsonValue가 선언된 toString()을 사용한다.
 

@Test
fun testJsonValueOnToString() {
    val objectMapper = ObjectMapper().registerKotlinModule()
    val response = MemberResponse(Member(1, "노력남자"))

    assertEquals("""{"member":"1-노력남자"}""".trimIndent(), objectMapper.writeValueAsString(response))
}

 

enum + @JsonValue

 
enum도 마찬가지로 프로퍼티, getter, 인자가 없는 메소드에 붙일 수 있다.
 
class에 사용하는 거랑 동일한 부분은 테스트하지 않겠다.
 
class랑 다른 건 enum에 선언된 @JsonValue는 직렬화, 역직렬화에 모두 사용된다는 점이다.
(단, @JsonCreator가 있는 경우 역직렬화에 사용되지 않음)
 
아래 User를 역직렬화해서 잘 동작하는지 테스트해보겠다.
 

class User(
    val userType: UserType
) {

    enum class UserType(
        @JsonValue val code: Int
    ) {
        NORMAL(0),
        ADMIN(1);
    }
}


@JsonValue를 이용해서 역직렬화가 이루어진다.
 

@Test
fun testJsonValue() {
    val objectMapper = ObjectMapper().registerKotlinModule()
    val json = """
        {
            "userType": "0"
        }            
    """.trimIndent()

    assertEquals(User.UserType.NORMAL, objectMapper.readValue<User>(json).userType)
}
반응형

댓글