[코틀린 인 액션] CH10 애노테이션과 리플렉션(1)

0

코틀린 인 액션

목록 보기
13/13
post-thumbnail

[코틀린 인 액션] CH10 애노테이션과 리플렉션(1)

이 포스팅은 <Kotlin in Action>, 드미트리 제메로프 & 스베트라나 이사코바, 에이콘출판사(2017)을 읽고 개인 학습용으로 정리한 글입니다.

10.1 애노테이션 선언과 적용

10.1.1 애노테이션 적용

  • 코틀린에서 자바와 같은 방법으로 애노테이션 사용

  • 애노테이션에 인자를 넘길 때: 일반 함수와 마찬가지로 괄호 안에 인자 전달
    (가능한 애노테이션 인자: 원시 타입 값, 문자열, enum 클래스 참조, 다른 애노테이션 클래스, ...)

    • 다른 애노테이션을 인자로 지정할 때: 애노테이션 앞 @ 넣으면 X
    • 배열을 인자로 지정할 때: arrayOf 함수 사용
  • 애노테이션 인자는 컴파일 시점에 알 수 있어야
    -> 임의의 프로퍼티를 인자로 지정할 수 X
    -> (파일의 맨 위 또는 object 안에 선언된) const 변경자가 붙은 프로퍼티 인자로 지정 가능

  • ⚡자바와 달리 코틀린에서는 애노테이션 인자로 임의의 식 허용
    ex. @Suppress

10.1.2 애노테이션 대상

  • 사용 지점 대상(use-site target) 선언: 애노테이션을 붙일 요소 정할 수 O
    @사용 지점 대상:애노테이션 이름

  • 사용 지점 대상을 지원하는 대상:

    • property: 프로퍼티 전체 (자바에서 선언된 애노테이션에서는 사용 X)
    • field: 프로퍼티에 의해 생성되는 뒷받침하는 필드
    • get: 프로퍼티 게터
    • set: 프로퍼티 세터
    • receiver: 확장 함수나 프로퍼티의 수신 객체 파라미터
    • param: 생성자 파라미터
    • setparam: 새터 파라미터
    • delegate: 위임 프로퍼티의 위임 인스턴스를 담아둔 필드
    • file: 파일 안에 선언된 최상위 함수와 프로퍼티를 담아두는 클래스

10.1.3 애노테이션을 활용한 JSON 직렬화 제어

  • 제이키드: JSON 직렬화를 위한 순수 코틀린 라이브러리

  • JSON에는 객체 타입 저장되지 X
    -> JSON 데이터로부터 인스턴스를 만들려면 타입 인자로 클래스 명시 필요

  • 애노테이션을 횔용해 객체 직렬화/역직렬화 방법 제어 가능

    • @JsonExclude: 직렬화/역직렬화 시 프로퍼티 무시 (반드시 프로터피 디폴트 값 지정해야)
    • @JsonName: 프로퍼티를 표현하는 키,값 쌍의 키를 프로퍼티 이름 대신 지정한 이름 사용

10.1.4 애노테이션 선언

  • 애노테이션 선언 구문: class 앞에 annotation 구분자

  • 애노테이션 클래스: 오직 선언이나 식과 관련있는 메타데이터의 구조 정의
    -> 내부에 아무 코드도 들어있을 수 X

  • 파라미터가 있는 애노테이션 정의: 애노테이션 클래스의 주 생성자에 파라미터 선언
    -> 단, 모든 파라미터 앞에 val 붙여야

10.1.5 메타애노테이션: 애노테이션을 처리하는 방법 제어

  • 자바와 마찬가지로 코틀린 애노테이션 클래스에 애노테이션 붙일 수 O

  • 애노테이션 클래스에 붙일 수 있는 애노테이션: 메타애노테이션
    -> 컴파일러가 애노테이션을 처리하는 방법 제어

  • @Target: 애노테이션을 적용할 수 있는 요소의 유형 지정 메타애노테이션
    -> 구체적인 @Target을 지정하지 않으면 모든 선언에 적용 가능

  • AnnotationTarget: 애노테이션이 붙을 수 있는 대상을 정의해둔 enum
    ex. Annotation.CLASS, Annotation.METHOD, ...

  • 메타애노테이션을 직접 만들어야한다면 ANNOTATION_CLASS를 대상으로 지정

@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class BindingAnnotation

@BindingAnnotation
annotation class MyBinding
  • ⭐대상을 PROPERTY로 지정한 애노테이션은 자바 코드에서 사용 불가
    -> AnnotationTarget.FIELD를 두 번째 대상으로 추가해야

  • ⚡@Retention: 정의 중인 애노테이션 클래스를 소스 수준에서만 유지할 지, .class 파일에 저장할 지, 실행 시점에 리플렉션을 사용해 접근할 수 있게 할 지 지정 메타애노테이션

  • 코틀린에서는 기본적으로 애니테이션의 @Retention을 RUNTIME으로 지정

10.1.6 애노테이션 파라미터로 클래스 사용

  • 어떤 클래스를 선언 메타데이터로 참조 필요할 경우
    -> 클래스 참조를 파라미터로 하는 애노테이션 클래스 정의
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
)
  • 직렬화된 Person 인스턴스를 역직렬화할 때:
    -> company 프로퍼티를 표현하는 JSON을
    -> 제이키드는 그 프로퍼티 값에 해당하는 JSON을 역직렬화하며 CompanyImpl 인스턴스 생성
    -> 해당 인스턴스를 Person 인스턴스의 company 프로퍼티에 설정
  • DeserializeInterface 애노테이션 정의:
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>의 하위 타입이 된다(공변성)

10.1.7 애노테이션 파라미터로 제네릭 클래스 받기

  • 기본적으로 제이키드는 원시 타입이 아닌 프로퍼티를 중첩된 객체로 직렬화
    -> 이런 기본 동작을 변경하고 싶으면 값을 직렬화하는 로직 직접 제공해야

  • @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<*>>
)
  • 클래스를 애노테이션 인자로 받아야할 때 패턴
    • 클래스를 인자로 받는 경우: 파라미터 타입 KClass<out 허용할 클래스 이름>
    • 제네릭 클래스를 인자로 받는 경우: 파라미터 타입 KClass<out 허용할 클래스 이름<*>>

profile
Be able to be vulnerable, in search of truth

0개의 댓글