feat : 어노테이션 기반의 직렬화 예제 코드 추가
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
package com.banjjoknim.playground.jackson.common
|
||||
|
||||
data class Car(
|
||||
val name: String,
|
||||
val price: Int = 0,
|
||||
val owner: Owner
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.banjjoknim.playground.jackson.common
|
||||
|
||||
import com.banjjoknim.playground.jackson.jsonserialize.UsingJsonSerializeAnnotationCarSerializer
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
|
||||
data class Car(
|
||||
val name: String,
|
||||
val price: Int = 10000000,
|
||||
val owner: Owner = Owner()
|
||||
)
|
||||
|
||||
data class CarUsingNoAnnotation(
|
||||
val name: String = "banjjoknim",
|
||||
val secret: String = "secret",
|
||||
val price: Int = 10000000,
|
||||
val owner: Owner = Owner()
|
||||
)
|
||||
|
||||
data class CarUsingJsonSerializeAnnotation(
|
||||
val name: String = "banjjoknim",
|
||||
@JsonSerialize(using = UsingJsonSerializeAnnotationCarSerializer::class)
|
||||
val secret: String = "secret",
|
||||
val price: Int = 10000000,
|
||||
val owner: Owner = Owner()
|
||||
)
|
||||
|
||||
data class CarUsingSecretAnnotation(
|
||||
val name: String = "banjjoknim",
|
||||
@field:Secret
|
||||
val secret: String = "secret",
|
||||
val price: Int = 10000000,
|
||||
val owner: Owner = Owner()
|
||||
)
|
||||
@@ -1,3 +1,3 @@
|
||||
package com.banjjoknim.playground.jackson.common
|
||||
|
||||
data class Owner(val name: String, val age: Int)
|
||||
data class Owner(val name: String = "ban", val age: Int = 30)
|
||||
|
||||
@@ -9,6 +9,6 @@ import com.fasterxml.jackson.annotation.JacksonAnnotation
|
||||
* @see com.fasterxml.jackson.annotation.JacksonAnnotationsInside
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@JacksonAnnotation // Jackson 에서 이 어노테이션을 인식할 수 있게 만들어준다.
|
||||
@Target(AnnotationTarget.FIELD) // 현재 상황에서는 PROPERTY 로 적용할 경우 제대로 적용되지 않는다. 아마 어노테이션 자체가 자바 기반으로 사용되어 PROPERTY 를 인식하지 못하는 것 같다(자바에서는 PROPERTY 타입을 사용할 수 없음).
|
||||
@JacksonAnnotation // NOTE: important; MUST be considered a 'Jackson' annotation to be seen(or recognized otherwise via AnnotationIntrospect.isHandled())
|
||||
annotation class Secret
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.banjjoknim.playground.jackson.jsonserialize
|
||||
|
||||
import com.banjjoknim.playground.jackson.common.Car
|
||||
import com.banjjoknim.playground.jackson.common.Secret
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.introspect.Annotated
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedMember
|
||||
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
|
||||
/**
|
||||
@@ -16,9 +20,12 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
*
|
||||
* JsonSerializer<T> 만 확장할 경우엔 애노테이션 정보를 얻을 수 없다. 추가적으로 ContextualSerializer 인터페이스를 구현해주면 createContextual() 메서드를 구현해줘야 하는데 두번째 인자로 넘어오는 BeanProperty 를 이용해 애노테이션 정보를 구할 수 있다.
|
||||
*
|
||||
* ContexutalSerializer 를 사용하는 방법은 [TestContextualSerialization](https://github.com/FasterXML/jackson-databind/blob/master/src/test/java/com/fasterxml/jackson/databind/contextual/TestContextualSerialization.java) 참고하도록 한다.
|
||||
*
|
||||
* Custom Serializer 가 JsonSerializer<T> 와 ContextualSerialier 를 모두 구현할 경우 createContextual() 함수가 먼저 호출된다.
|
||||
*
|
||||
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
* @see com.fasterxml.jackson.databind.ser.std.StringSerializer
|
||||
* @see com.fasterxml.jackson.databind.ser.ContextualSerializer
|
||||
*/
|
||||
class CarSerializer : StdSerializer<Car>(Car::class.java) {
|
||||
@@ -64,3 +71,40 @@ class CarNameOwnerNameSerializer : StdSerializer<Car>(Car::class.java) {
|
||||
gen.writeEndObject()
|
||||
}
|
||||
}
|
||||
|
||||
class UsingJsonSerializeAnnotationCarSerializer : StdSerializer<String>(String::class.java) {
|
||||
override fun serialize(value: String, gen: JsonGenerator, provider: SerializerProvider) {
|
||||
gen.writeString("****")
|
||||
}
|
||||
}
|
||||
|
||||
class SecretAnnotationSerializer : StdSerializer<String>(String::class.java) {
|
||||
override fun serialize(value: String, gen: JsonGenerator, provider: SerializerProvider) {
|
||||
gen.writeString("****")
|
||||
}
|
||||
}
|
||||
|
||||
class SecretAnnotationIntrospector : JacksonAnnotationIntrospector() {
|
||||
/**
|
||||
*
|
||||
* `@JsonIgnore` 를 적용했을 때 무시할지 여부를 판단하는 함수이다.
|
||||
*
|
||||
* 따라서 직렬화 / 역직렬화시 무시하고 싶은 프로퍼티가 있다면 이 함수를 override 하면 된다.
|
||||
*/
|
||||
override fun hasIgnoreMarker(m: AnnotatedMember): Boolean {
|
||||
return super.hasIgnoreMarker(m)
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 프로퍼티에 대해 어떤 Serializer 를 사용할 것인지 결정하는 함수이다.
|
||||
*
|
||||
* 따라서 특정 조건에 따라 직렬화를 하고싶다면 이 함수를 override 하면 된다.
|
||||
*/
|
||||
override fun findSerializer(a: Annotated): Any? {
|
||||
val annotation = a.getAnnotation(Secret::class.java)
|
||||
if (annotation != null) {
|
||||
return SecretAnnotationSerializer()
|
||||
}
|
||||
return super.findSerializer(a) // 기존 JacksonAnnotationIntrospector 의 것을 사용한다.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.banjjoknim.playground.jsonserialize
|
||||
package com.banjjoknim.playground.jackson.jsonserialize
|
||||
|
||||
import com.banjjoknim.playground.jackson.jsonserialize.CarNameOwnerNameSerializer
|
||||
import com.banjjoknim.playground.jackson.jsonserialize.CarNameOwnerSerializer
|
||||
import com.banjjoknim.playground.jackson.jsonserialize.CarNameSerializer
|
||||
import com.banjjoknim.playground.jackson.jsonserialize.CarPriceSerializer
|
||||
import com.banjjoknim.playground.jackson.jsonserialize.CarSerializer
|
||||
import com.banjjoknim.playground.jackson.common.Car
|
||||
import com.banjjoknim.playground.jackson.common.CarUsingJsonSerializeAnnotation
|
||||
import com.banjjoknim.playground.jackson.common.CarUsingNoAnnotation
|
||||
import com.banjjoknim.playground.jackson.common.CarUsingSecretAnnotation
|
||||
import com.banjjoknim.playground.jackson.common.Owner
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
@@ -25,13 +23,16 @@ import org.junit.jupiter.api.Test
|
||||
* @see com.fasterxml.jackson.databind.ser.std.BeanSerializerBase
|
||||
* @see com.fasterxml.jackson.databind.ser.BeanPropertyWriter
|
||||
*/
|
||||
class CarSerializerTest {
|
||||
class CarSerializersTest {
|
||||
|
||||
private lateinit var mapper: ObjectMapper
|
||||
|
||||
companion object {
|
||||
private val owner = Owner("ban", 30)
|
||||
private val car = Car("banjjoknim", 10_000_000, owner)
|
||||
private val carUsingNoAnnotation = CarUsingNoAnnotation()
|
||||
private val carUsingJsonSerializeAnnotation = CarUsingJsonSerializeAnnotation()
|
||||
private val carUsingSecretAnnotation = CarUsingSecretAnnotation()
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@@ -122,5 +123,39 @@ class CarSerializerTest {
|
||||
// then
|
||||
assertThat(result).isEqualTo("""{"name":"banjjoknim","owner":{"name":"ban"}}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `아무 어노테이션도 적용하지 않고 직렬화한다`() {
|
||||
// given
|
||||
|
||||
// when
|
||||
val actual = mapper.writeValueAsString(carUsingNoAnnotation)
|
||||
|
||||
// then
|
||||
assertThat(actual).isEqualTo("""{"name":"banjjoknim","secret":"secret","price":10000000,"owner":{"name":"ban","age":30}}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `@JsonSerialize 어노테이션을 적용하여 직렬화한다`() {
|
||||
// given
|
||||
|
||||
// when
|
||||
val actual = mapper.writeValueAsString(carUsingJsonSerializeAnnotation)
|
||||
|
||||
// then
|
||||
assertThat(actual).isEqualTo("""{"name":"banjjoknim","secret":"****","price":10000000,"owner":{"name":"ban","age":30}}""")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `@Secret 어노테이션을 적용하여 직렬화한다`() {
|
||||
// given
|
||||
mapper.setAnnotationIntrospector(SecretAnnotationIntrospector())
|
||||
|
||||
// when
|
||||
val actual = mapper.writeValueAsString(carUsingSecretAnnotation)
|
||||
|
||||
// then
|
||||
assertThat(actual).isEqualTo("""{"name":"banjjoknim","secret":"****","price":10000000,"owner":{"name":"ban","age":30}}""")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user