- 애노테이션 적용과 정의
- 리플렉션을 사용해 실행 시점에 객체 내부 관찰
- 코틀린 실전 프로젝트 예제
어떤 함수를 호출하려면 그 함수가 정의된 클래스의 이름과 함수 이름, 파라미터 이름 등을 알아야 한다
-> 그런 제약을 벗어나게 해주는 것이 애노테이션 과 리플렉션
애노태이션을 사용하면
라이브러리가 요구하는 의미를 클래스에게 부여할 수 있다
리플렉션을 사용하면
실행 시점에 컴파일러 내부 구조를 분석할 수 있다
애노테이션을 적용하려면 적용하려는 대상 앞에 애노테이션을 붙이면 된다
-> 함수/클래스 등 여러 다른 코드 구성 요소에 애노테이션을 붙일 수 있다
@Deprecated 애노테이션
-> 특정 함수, 클래스, 필드, 생성자 등에 달아 더이상 사용하지 말라는 경고를 주기 위한 용도이다
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"))
fun remove(index: Int) { ... }
fun main() {
remove(2)
}
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)")
, level = DeprecationLevel.ERROR)
fun remove(index: Int) { ... }
fun main() {
remove(2)
}
애노테이션 인자로는 원시 타입의 값, 문자열, enum, 클래스 참조, 다른 애노테이션 클래스, 지금까지 말한 요소들로 이뤄진 배열이 들어갈 수 있다
@MyAnnotation(MyClass::class)
처럼 ::class를 클래스 이름 뒤에 넣어야 한다@
를 넣지 않아야 한다@RequestMapping(path = arrayOf("/foo","/bar"))
처럼JavaAnnotationWithArrayValue("abc","foo")
처럼 arrayOf 함수를 안써도 된다const 변경자
를 붙여야 한다const
가 붙은 프로퍼티를 컴파일 시점 상수로 취급한다-> 애노테이션을 붙일 때 이런 요소 중 어떤 요소에 애노테이션을 붙일지 표시할 필요가 있다
get은 @Rule 애노테이션
을 프로퍼티 게터에 적용하라는 뜻이다
제이유닛(JUnit)에서는 각 테스트 메소드 앞에 그 메소드를 실행하기 위한 규칙을 지정할 수 있다
-> 규칙을 지정하려면 공개 필드 / 메소드 앞에 @Rule
을 붙여야 한다
@Rule
은 필드에 적용되지만
🔥코틀린의 필드는 기본적으로 비공개이기 때문에 예외 발생할 수도 있다
코틀린으로 애노테이션을 선언하면 직접 사용할 수 있는 애노테이션을 만들 수 있다
- property
프로퍼티 전체. 자바에서 선언된 애노테이션에는 이 사용 지점 대상을 사용할 수 없다- field
프로퍼티에 의해 생성되는 (뒷받침하는) 필드- get
프로퍼티 게터- set
프로퍼티 세터- reciver
확장 함수나 프로퍼티의 수신 객체 파라미터- param
생성자 파라미터- setparam
세터 파라미터- delegate
위임 프로퍼티의 위임 인스턴스를 담아둔 필드- file
파일 안에 선언된 최상위 함수와 프로퍼티를 담아두는 클래스
@Suppress
애노테이션을 사용하는 고전적인 예제
-> 객체 직렬화 제어
예제) Person 클래스를 직렬화하고 역직렬화
- 직렬화
data class Person(val name: String, val age: Int)
>>> val person = Person("Kim", 29)
>>> println(serialize(person))
{"age": 29, "name": "Kim"}
-> 객체 인스턴스의 JSON 표현은 키/값 쌍으로 이뤄진 객체를 표현한다
키/값 쌍은 각 인스턴스의 프로퍼티 이름과 값을 표현한다
- 역직렬화
>>> val json = """{"name": "Kim", "age": 29}"""
>>> println(deserialize<Person>(json))
Person(name=Kim,age=29)
-> JSON에는 객체의 타입이 저장되지 않기 때문에
JSON 데이터로부터 인스턴스를 만들려면 타입 인자로 클래스를 명시해야 한다
@JsonExclude
애노테이션
직렬화나 역직렬화 시 그 프로퍼티를 무시할 수 있다
-> 프로퍼티에는 반드시 디폴트 값을 지정해야 한다@JsonName
애노테이션
프로퍼티를 표현하는 키/값 쌍의 키로 프로퍼티 이름 대신 애노테이션이 지정한 이름을 쓰게할 수 있다
data class Person(
@JsonName("alias") val firstName: String,
@JsonExclude val age: Int? = null
)
애노테이션 클래스에도 애노테이션을 붙일 수 있다
가장 많이 쓰이는 매타애노테이션은 @Target
@Targer
메타애노테이션은 애노테이션을 적용할 수 있는 요소의 유형을 지정한다
애노테이션 클래스에 대해 구체적인 @Target
을 지정하지 않으면 모든 선언에 적용할 수 있는 애노테이션이 된다
-> 💣하지만, 제이키드 라이브러리는 프로퍼티 애노테이션만을 사용하므로
애노테이션 클래스에 꼭 @Target
을 지정해야 한다
애노테이션이 붙을 수 있는 대상이 정의된 이넘(enum)은 AnnotationTarget이다
-> 둘 이상의 대상을 한 꺼번에 처리할 수도 있다
ex) @Target(AnnotationTarget.CLASS, AnnotationTarget.METHOD)
클래스 참조를 파라미터로 하는 애노테이션 클래스를 선언하면
-> 어떤 클래스를 선언 메타데이터로 참조할 수 있다
@DeserializeInterface
@DeserialzeInterface 사용법
interface Company {
val name: String
}
data class CompanyImpl(override val name: String): Company
data class Person(
val name: String,
@DeserialzeInterface(CompanyImpl::class) val company: Company
)