@JsonTypeInfo
인터페이스나 추상클래스를 이용하여 다형성을 구현한 경우, 실제 클래스가 무엇인지 알려주는 설정을 하는 어노테이션
json type 이라는 메타정보를 생성하여 사용하고 이 메타정보는 json 에 추가 프로퍼티로 들어간다. 이 추가 프로퍼티는 직렬화에 관여되지 않는다.
속성으로 ID, AS, property 를 갖는데, 이것은 사용예시를 보면서 하나씩 보자.
1. @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
// @class 라는 추가 프로퍼티가 생기고 패키지.클래스명으로 값이 자동으로 세팅됨
// @JsonSubTypes 을 안줘도 자동으로 서브 클래스를 등록한다.(이건 확인 필요)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
interface Shape
data class Rectangle(
val w: Int,
val h: Int
): Shape
data class Circle(
val radius: Int
): Shape
data class View(
val shapes: List<Shape>,
val shape: Shape
)
Serialize 결과
{"shapes":[{"@class":"models.Rectangle","w":10,"h":20},{"@class":"models.Rectangle","w":1000,"h":2000},{"@class":"models.Circle","radius":7}],"shape":{"@class":"models.Circle","radius":777}}
2. @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
// 사용자가 직접 준 이름을 추가 프로퍼티의 키로 사용
// 값은 클래스이름이 자동으로 세팅
// @class 보다 명확함
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
Serialize 결과
{"shapes":[{"type":"Rectangle","w":10,"h":20},{"type":"Rectangle","w":1000,"h":2000},{"type":"Circle","radius":7}],"shape":{"type":"Circle","radius":777}}
3. 기존의 프로퍼티를 그대로 사용
// EXISTING_PROPERTY 으로 설정하고 property 이름을 주면 기존 필드를 이용할 수 있음
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "subType")
@JsonSubTypes(
JsonSubTypes.Type(Rectangle::class),
JsonSubTypes.Type(Circle::class),
)
interface Shape{
val subType: String
}
data class Rectangle(
val w: Int,
val h: Int
): Shape {
override val subType: String = this::class.java.simpleName
}
data class Circle(
val radius: Int
): Shape {
override val subType: String = this::class.java.simpleName
}
결과
{"shapes":[{"w":10,"h":20,"subType":"Rectangle"},{"w":1000,"h":2000,"subType":"Rectangle"},{"radius":7,"subType":"Circle"}],"shape":{"radius":777,"subType":"Circle"}}
@JsonSubTypes
1. @JsonTypeInfo 외에 서브클래스를 모두 등록하여야 실제 동작하는데, 서브클래스를 알려주기 위해 사용하는 어노테이션
// 자동으로 클래스 이름이 json type 프로퍼티의 값으로 들어간다.
@JsonSubTypes(
JsonSubTypes.Type(Rectangle::class),
JsonSubTypes.Type(Circle::class),
)
2. 서브클래스의 매핑값을 직접 줄 수도 있다.
enum class ShapeType{
RECTANGLE,
CIRCLE;
object Constants {
const val RECTANGLE = "R"
const val CIRCLE = "C"
}
}
// JsonSubType 의 name에 직접 매핑할 값을 넣어주어도 됨
// 단, 이때는 각각의 클래스에 @JsonTypeName 어노테이션을 주어야 함
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
JsonSubTypes.Type(Rectangle::class, name = ShapeType.Constants.RECTANGLE),
JsonSubTypes.Type(Circle::class, name = ShapeType.Constants.CIRCLE),
)
interface Shape
@JsonTypeName(ShapeType.Constants.RECTANGLE)
data class Rectangle(
val w: Int,
val h: Int
): Shape
@JsonTypeName(ShapeType.Constants.CIRCLE)
data class Circle(
val radius: Int
): Shape
data class View(
val shapes: List<Shape>,
val shape: Shape
)
결과
{"shapes":[{"type":"R","w":10,"h":20},{"type":"R","w":1000,"h":2000},{"type":"C","radius":7}],"shape":{"type":"C","radius":777}}
Custom Deserializer
작성중
kotlinx.serialization
작성중
'SW 공부' 카테고리의 다른 글
[Kotlin] 코루틴 기초 (0) | 2021.03.19 |
---|---|
[Ssh] ssh 키를 이용하여 로그인하기 (0) | 2020.11.01 |
[Redis] redis 를 이용한 global session 관리 (0) | 2020.10.15 |
[Spring] service 테스트 작성 요령 (0) | 2020.07.06 |
[JPA] 복합키(Composite Key) 생성 및 관계 맺기 (0) | 2020.04.23 |