이 포스팅은 <Kotlin in Action>, 드미트리 제메로프 & 스베트라나 이사코바, 에이콘출판사(2017)을 읽고 개인 학습용으로 정리한 글입니다.
코틀린에서 자바와 같은 방법으로 애노테이션 사용
애노테이션에 인자를 넘길 때: 일반 함수와 마찬가지로 괄호 안에 인자 전달
(가능한 애노테이션 인자: 원시 타입 값, 문자열, enum 클래스 참조, 다른 애노테이션 클래스, ...)
애노테이션 인자는 컴파일 시점에 알 수 있어야
-> 임의의 프로퍼티를 인자로 지정할 수 X
-> (파일의 맨 위 또는 object 안에 선언된) const 변경자가 붙은 프로퍼티 인자로 지정 가능
⚡자바와 달리 코틀린에서는 애노테이션 인자로 임의의 식 허용
ex. @Suppress
사용 지점 대상(use-site target) 선언: 애노테이션을 붙일 요소 정할 수 O
@사용 지점 대상:애노테이션 이름
사용 지점 대상을 지원하는 대상:
제이키드: JSON 직렬화를 위한 순수 코틀린 라이브러리
JSON에는 객체 타입 저장되지 X
-> JSON 데이터로부터 인스턴스를 만들려면 타입 인자로 클래스 명시 필요
애노테이션을 횔용해 객체 직렬화/역직렬화 방법 제어 가능
애노테이션 선언 구문: class 앞에 annotation 구분자
애노테이션 클래스: 오직 선언이나 식과 관련있는 메타데이터의 구조 정의
-> 내부에 아무 코드도 들어있을 수 X
파라미터가 있는 애노테이션 정의: 애노테이션 클래스의 주 생성자에 파라미터 선언
-> 단, 모든 파라미터 앞에 val 붙여야
자바와 마찬가지로 코틀린 애노테이션 클래스에 애노테이션 붙일 수 O
애노테이션 클래스에 붙일 수 있는 애노테이션: 메타애노테이션
-> 컴파일러가 애노테이션을 처리하는 방법 제어
@Target: 애노테이션을 적용할 수 있는 요소의 유형 지정 메타애노테이션
-> 구체적인 @Target을 지정하지 않으면 모든 선언에 적용 가능
AnnotationTarget: 애노테이션이 붙을 수 있는 대상을 정의해둔 enum
ex. Annotation.CLASS, Annotation.METHOD, ...
메타애노테이션을 직접 만들어야한다면 ANNOTATION_CLASS를 대상으로 지정
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class BindingAnnotation
@BindingAnnotation
annotation class MyBinding
⚡@Retention: 정의 중인 애노테이션 클래스를 소스 수준에서만 유지할 지, .class 파일에 저장할 지, 실행 시점에 리플렉션을 사용해 접근할 수 있게 할 지 지정 메타애노테이션
코틀린에서는 기본적으로 애니테이션의 @Retention을 RUNTIME으로 지정
interface Company{
val name: String
}
data class CompanyImpl(override val name: String):Company
data class Person(
val name:String,
@DeserializeInterface(CompanyImpl::class) val company:Company
)
annotation class DeserializeInterface(val targetClass: KClass<out Any>)
KClass: 자바 java.lang.Class 타입과 같은 역할을 하는 코틀린 타입
-> 코틀린 클래스에 대한 참조 저장할 때 사용
KClass의 타입 파라미터: 이 KClass의 인스턴스가 가리키는 코틀린 타입 지정
ex. CompanyImpl::class의 타입: KClass<CompanyImpl>
⭐KClass 타입 파라미터를 쓸 때 out 변경자 필요
-> 모든 코틀린 타입 T에 대해 KClass<T>가 KClass<out Any>의 하위 타입이 된다(공변성)
기본적으로 제이키드는 원시 타입이 아닌 프로퍼티를 중첩된 객체로 직렬화
-> 이런 기본 동작을 변경하고 싶으면 값을 직렬화하는 로직 직접 제공해야
@CustomSerializer: 커스텀 직렬화 클래스에 대한 참조를 애노테이션 인자로 받음
직렬화 클래스는 ValueSerializer 인터페이스를 구현해야
ValueSerializer 클래스는 제네릭 타입-> 타입 파라미터 존재
interface ValueSerializer<T>{
fun toJSONValue(value: T):Any?
fun fromJAONValue(JsonValue: Any?):T
}
ValueSerializer 클래스는 제네릭 타입 -> 타입 파라미터 존재
-> ValueSerializer 타입을 참조하려면 타입 파라미터 제공해야
CustomSerializer 애노테이션 정의:
-> ValueSerializer를 구현하는 타입만 인자로 받도록 함
-> ValueSerializer의 타입 파라미터로 스타 프로젝션 사용
annotation class CustomSerializer(
val serializerClass: KClass<out ValueSerializer<*>>
)