Merge pull request #5 from banjjoknim/jackson

ContextualSerializer 를 사용하는 직렬화 예제 코드 추가
This commit is contained in:
Colt
2022-03-13 22:33:38 +09:00
committed by GitHub
3 changed files with 67 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
package com.banjjoknim.playground.jackson.common package com.banjjoknim.playground.jackson.common
import com.banjjoknim.playground.jackson.jsonserialize.ContextualCarSerializer
import com.banjjoknim.playground.jackson.jsonserialize.UsingJsonSerializeAnnotationCarSerializer import com.banjjoknim.playground.jackson.jsonserialize.UsingJsonSerializeAnnotationCarSerializer
import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.databind.annotation.JsonSerialize
@@ -16,7 +17,7 @@ data class CarUsingNoAnnotation(
val owner: Owner = Owner() val owner: Owner = Owner()
) )
data class CarUsingJsonSerializeAnnotation( data class CarUsingJsonSerializeAnnotationCarSerializer(
val name: String = "banjjoknim", val name: String = "banjjoknim",
@JsonSerialize(using = UsingJsonSerializeAnnotationCarSerializer::class) @JsonSerialize(using = UsingJsonSerializeAnnotationCarSerializer::class)
val secret: String = "secret", val secret: String = "secret",
@@ -24,6 +25,23 @@ data class CarUsingJsonSerializeAnnotation(
val owner: Owner = Owner() 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( data class CarUsingSecretAnnotation(
val name: String = "banjjoknim", val name: String = "banjjoknim",
@field:Secret("****") @field:Secret("****")

View File

@@ -4,6 +4,8 @@ import com.banjjoknim.playground.jackson.common.Car
import com.banjjoknim.playground.jackson.common.Secret import com.banjjoknim.playground.jackson.common.Secret
import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.BeanDescription 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.SerializationConfig
import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.introspect.Annotated 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.module.SimpleModule
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter import com.fasterxml.jackson.databind.ser.BeanPropertyWriter
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier import com.fasterxml.jackson.databind.ser.BeanSerializerModifier
import com.fasterxml.jackson.databind.ser.ContextualSerializer
import com.fasterxml.jackson.databind.ser.std.StdSerializer 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` 정보를 어떻게 처리할지에 대한 정보가 정의되어 있는 클래스다. * AnnotationIntrospector 를 상속한 JacksonAnnotationIntrospector 은 Jackson 라이브러리가 직렬화/역직렬화시 `JacksonAnnotation` 정보를 어떻게 처리할지에 대한 정보가 정의되어 있는 클래스다.
* *

View File

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