feat : ContextualSerializer 를 사용하는 직렬화 예제 코드 추가

This commit is contained in:
banjjoknim
2022-03-13 22:25:23 +09:00
parent 3af79e6619
commit d942818cb7
3 changed files with 67 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
package com.banjjoknim.playground.jackson.common
import com.banjjoknim.playground.jackson.jsonserialize.ContextualCarSerializer
import com.banjjoknim.playground.jackson.jsonserialize.UsingJsonSerializeAnnotationCarSerializer
import com.fasterxml.jackson.databind.annotation.JsonSerialize
@@ -16,7 +17,7 @@ data class CarUsingNoAnnotation(
val owner: Owner = Owner()
)
data class CarUsingJsonSerializeAnnotation(
data class CarUsingJsonSerializeAnnotationCarSerializer(
val name: String = "banjjoknim",
@JsonSerialize(using = UsingJsonSerializeAnnotationCarSerializer::class)
val secret: String = "secret",
@@ -24,6 +25,23 @@ data class CarUsingJsonSerializeAnnotation(
val owner: Owner = Owner()
)
data class CarUsingContextualSerializerWithSecretAnnotation(
val name: String = "banjjoknim",
@JsonSerialize(using = ContextualCarSerializer::class)
@field:Secret("hello world!!")
val secret: String = "secret",
val price: Int = 10000000,
val owner: Owner = Owner()
)
data class CarUsingContextualSerializerWithNoSecretAnnotation(
val name: String = "banjjoknim",
@JsonSerialize(using = ContextualCarSerializer::class)
val secret: String = "secret",
val price: Int = 10000000,
val owner: Owner = Owner()
)
data class CarUsingSecretAnnotation(
val name: String = "banjjoknim",
@field:Secret("****")

View File

@@ -4,6 +4,8 @@ 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.BeanDescription
import com.fasterxml.jackson.databind.BeanProperty
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializationConfig
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.introspect.Annotated
@@ -12,6 +14,7 @@ import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier
import com.fasterxml.jackson.databind.ser.ContextualSerializer
import com.fasterxml.jackson.databind.ser.std.StdSerializer
/**
@@ -83,6 +86,24 @@ class UsingJsonSerializeAnnotationCarSerializer : StdSerializer<String>(String::
}
}
class ContextualCarSerializer(
private val substituteValue: String = "this is default value in ContextualCarSerializer"
) : StdSerializer<String>(String::class.java), ContextualSerializer {
override fun serialize(value: String, gen: JsonGenerator, provider: SerializerProvider) {
gen.writeString(substituteValue)
}
override fun createContextual(provider: SerializerProvider, property: BeanProperty): JsonSerializer<*> {
val annotation = property.getAnnotation(Secret::class.java)
if (annotation != null) {
return ContextualCarSerializer(annotation.substituteValue)
}
return ContextualCarSerializer()
// JsonMappingException: Can not write a field name, expecting a value (through reference chain: com.banjjoknim.playground.jackson.common.CarUsingContextualSerializerWithNoSecretAnnotation["secret"])
// return provider.findKeySerializer(property.type, property)
}
}
/**
* AnnotationIntrospector 를 상속한 JacksonAnnotationIntrospector 은 Jackson 라이브러리가 직렬화/역직렬화시 `JacksonAnnotation` 정보를 어떻게 처리할지에 대한 정보가 정의되어 있는 클래스다.
*

View File

@@ -1,7 +1,9 @@
package com.banjjoknim.playground.jackson.jsonserialize
import com.banjjoknim.playground.jackson.common.Car
import com.banjjoknim.playground.jackson.common.CarUsingJsonSerializeAnnotation
import com.banjjoknim.playground.jackson.common.CarUsingContextualSerializerWithNoSecretAnnotation
import com.banjjoknim.playground.jackson.common.CarUsingContextualSerializerWithSecretAnnotation
import com.banjjoknim.playground.jackson.common.CarUsingJsonSerializeAnnotationCarSerializer
import com.banjjoknim.playground.jackson.common.CarUsingNoAnnotation
import com.banjjoknim.playground.jackson.common.CarUsingSecretAnnotation
import com.banjjoknim.playground.jackson.common.Owner
@@ -32,7 +34,11 @@ class CarSerializersTest {
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 carUsingJsonSerializeAnnotationCarSerializer = CarUsingJsonSerializeAnnotationCarSerializer()
private val carUsingContextualSerializerWithSecretAnnotation =
CarUsingContextualSerializerWithSecretAnnotation()
private val carUsingContextualSerializerWithNoSecretAnnotation =
CarUsingContextualSerializerWithNoSecretAnnotation()
private val carUsingSecretAnnotation = CarUsingSecretAnnotation()
}
@@ -141,12 +147,26 @@ class CarSerializersTest {
// given
// when
val actual = mapper.writeValueAsString(carUsingJsonSerializeAnnotation)
val actual = mapper.writeValueAsString(carUsingJsonSerializeAnnotationCarSerializer)
// then
assertThat(actual).isEqualTo("""{"name":"banjjoknim","secret":"****","price":10000000,"owner":{"name":"ban","age":30}}""")
}
@Test
fun `ContextualSerializer 를 상속 받은 구현체를 이용해서 직렬화한다`() {
// given
// when
val actualWithSecretAnnotation = mapper.writeValueAsString(carUsingContextualSerializerWithSecretAnnotation)
val actualWithNoSecretAnnotation =
mapper.writeValueAsString(carUsingContextualSerializerWithNoSecretAnnotation)
// then
assertThat(actualWithSecretAnnotation).isEqualTo("""{"name":"banjjoknim","secret":"hello world!!","price":10000000,"owner":{"name":"ban","age":30}}""")
assertThat(actualWithNoSecretAnnotation).isEqualTo("""{"name":"banjjoknim","secret":"this is default value in ContextualCarSerializer","price":10000000,"owner":{"name":"ban","age":30}}""")
}
@Test
fun `@Secret 어노테이션, AnnotationIntrospector 을 적용하여 직렬화한다`() {
// given
@@ -239,7 +259,10 @@ class CarSerializersTest {
// when
mapper.setAnnotationIntrospector(
AnnotationIntrospector.pair(SecretAnnotationIntrospector(), originalAnnotationIntrospector) // 내부 구현은 아래와 같다.
AnnotationIntrospector.pair(
SecretAnnotationIntrospector(),
originalAnnotationIntrospector
) // 내부 구현은 아래와 같다.
// AnnotationIntrospectorPair(SecretAnnotationIntrospector(), originalAnnotationIntrospector)
)
val allIntrospectorNames = mapper.serializationConfig.annotationIntrospector.allIntrospectors()