Annotations and Reflection

Doyeon
4 min readNov 20, 2022

--

In this article, i will explain and summarize about Kotlin’s Annotations and Reflection.

  • Defining & Using annotation
  • Bulit in annotation
  • Class literals and callable references
  • Reflection API

Annotation

is a special kind of Kotlin class that allows you to define custom metadata and bind them to the elements of your source code-declarations, expressions or whole files.

  • means of attaching metadata to code.
  • A way of representing metadata.

Types of Annotation

  1. Built in annotation
  2. Meta annotation
  3. Custom annotation using Reflection & using Code Generation

How to apply?

In Kotlin, we apply an annotation by putting its name prefixed with the “@”symbol in front of a code element.

@Positive val amount: Float

Built in annotation

@Deprecated:특정 함수, 클래스, 필드, 생성자 등에 달아 더이상 사용하지 말라는 경고를 주기 위한 어노테이션

@SuppressWarning : 경고를 제외시켜준다.

@IntRange : Int value 범위를 제한해 준다

@JvmOverloads :함수 또는 생성자 파라미터에 default value가 설정되어 있을 경우 컴파일러가 default value 만큼의 오버로딩 함수를 만들어준다.

Class checkBoxSearchTextView @JvmOverloads constructor( 
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
): ConstraintLayout(context, attrs, defStyleAttr) {

}

//above example makes automatic overloading methods as below

CheckBoxSearhTextView(context: Context)
CheckBoxSearhTextView(context: Context, attrs: AttributeSet?)
CheckBoxSearhTextView(context: Context, attrs: AttributeSet?, defStyleAttr: Int)

How to declare?

In order to declare an annotation, we define a class and place the annotation keyword before the class. By their nature, declarations of annotation cannot contain any code.

annotation class Positive

Where to apply?

  • primitive types (Int, Byte, Short, Float, Double, Char, Boolean)
  • enumerations
  • class references
  • annotations
  • arrays

Meta annotation

When we declare our custom annotations, we should specify those

  • which code elements they might apply
  • where they should be stored

and annotations used to define this meta-info(additional attributes of the annotation) are called meta annotation. These can be used to make annotation class bounded and more powerful.

@Target

This meta-annotation specifies which code elements this annotation may refer to. It has a required parameter that must be an instance of the AnnotationTarget enumeration. You can refer below:

AnnotationTarget enumeration’s elements:

  • CLASS
  • ANNOTATION_CLASS
  • TYPE_PARAMETER
  • PROPERTY
  • FIELD
  • LOCAL_VARIABLE
  • VALUE_PARAMETER
  • CONSTRUCTOR
  • FUNCTION
  • PROPERTY_GETTER, PROPERTY_SETTER
  • TYPE
  • EXPRESSION
  • FILE
  • TYPEALIAS
@Target(AnnotationTarget.FUNCTION, annotionTarget.CLASS)
Annotation class TestAnnotation

Above code only targeting FUNCTION and CLASS so if try to put an annotation on field, it will create a compile error.

If we don’t specify, CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER is by default.

@Retention

This meta-annotation specifies scope of the annotation.

  • whether the annotation should be stored in the .class file
  • whether it should be visible for a reflection.

Its required parameter must be an instance of the AnnotationRetention enumeration as following:

  • SOURCE
  • BINARY
  • RUNTIME

by default is RUNTIME.

@Repeatable

This meta-annotation specifies whether an element might have multiple annotations of the same(single) type. This meta-annotation accepts no parameters.

@MustBeDocumented

This specifies whether the annotation’s documentation should be included in the generated documentation which is similar to Java’s @Documented. This meta-annotation accepts no parameters.

Custom annotation

When making annotation, there’s two way to make it.

  1. Using Reflection
  2. Using Code Generation

Reflection

Reflection is a technique that allows you to examine and modify your application structure at runtime. In other words, it gives you an access to runtime representations of classes, functions and properties.

  • It’s useful when your code has to work with classes that are not available at the compile time but still conforms to some common contract.
  • This can be dangerous and make the app’s 성능 저하 because it checks whether its parameter’s type correct whenever the function is called during runtime.

리플렉션

자바: (컴파일러) 자바소스코드 -> .class 바이트코드 -> (클래스 로더) 바이트 코드 -> JVM내 메모리 영역

: JVM 영역에 저장된 클래스의 정보를 꺼내와서 클래스 정보, 필드등을 사용할수있게 해준다.

클래스: 실행중인 어플리케이션의 클래스 정보와 인터페이스의 정보를 가진 클래스

클래스는 public 생성자가 존재하지 않는다
클래스 객체는 JVM에 의해 자동으로 생성된다

제공 기능:
- 클래스의 어노테이션 조회
- 생성자 조회
- 필드 조회
- 클래스 메서드 조회
- 부모 클래스, 인터페이스 조회

자동으로 생성된 클래스의 객체는 어떻게 가져오나?
1.{클래스타입}.class
2.{인스턴스}.getClass()
3.Class.forName(“{전체 도메인 네임}”)

쓰는이유?
프레임워크, 라이브러리에서 주로 사용
우리가 코딩을 할때에는 객체타입을 알지만, 프레임워크나 라이브러리는 우리가 생성한 객체가 어떤 타입인지 컴파일시점까지 알지 못하기때문에 리플렉션을 사용한다 (동적해결위해)

즉= 예를 들면 여러클래스에 적용해야하는데, 클래스가 만약 다 다르다면 object로 사용하는 경우가 생기는데, object의 타입을 모르때문에 메서드를 사용 못할때가 있는데, 리플렉션을 사용하게 되면 런타임때 읽어와 이러한 작업을 가능하게 해준다.

어노테이션: 주석이지만 작동 원리 역시 리플렉션이다.

원리:
1. 리플렉션을 통해 클래스나 메서드, 파라미터 정보를 가져온다
2. 리플렉션의 getAnnotation 등의 메서드를 통해 원하는 어노테이션이 붙어있는지 확인한다.
3. 어노테이션이 붙어있다면 원하는 로직을 수행한다
코틀린에서의 KClass는 자바의 java.lang.class에 해당하는 클래스이다. 클래스 안에있는 모든 선언을 열거하고 각 선언에 접근하거나 클래스의 상의 클래스 얻는 등의 작업이 가능하다.

객체를 얻기 위해선, javaClass 프로퍼티를 사용해 객체의 자바클래스를 얻을수있고, 코틀린 확장 프로퍼티를 통해 자바에서 코틀린 리플렉션API로 옮겨올수 있다.

코틀린 리플렉션API ( KClass, KCallable, KFunction, KProperty)
val kClass = person.javaClass.kotlin

KClass의 내부 선언은,

public interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier {

public val simpleName: String?
public val qualifiedName: String?
override val members: Collection<KCallable<*>>
public val constructors: Collection<KFunction<T>>

KCallable
이렇게 되어있고, 모든 멤버가 KCallable 인스턴스의 컬렉션이다. 이는 함수와 프로퍼티를 아우르는 공통 상위 인터페이스이며
Call 메서드가 존재한다.

Call메서드를 사용하면 함수나 프로퍼티의 게터를 호출할수있다.

  • KFunction

함수나 생성자를 표현하고, 함수에 적용 가능한 변경자 검사를 위한 프로퍼티만 존재한다.

  • KProperty
    Call 과 get 메서드를 호출할수있다
    최상위 수준이나 클래스 안에 정의된 프로퍼티만 리플렉션으로 가져올수있고 함수의 로컬 변수에는 접근할술없다.

단점:

  • 컴파일시점이 아니라 런타임 시점에서 클래스를 분석한다 -> JVM을 최적화할수 없기 때문에 성능저하 발생
  • 메서드 호출을 10만번 반복한 결과 7초 -> 170초 (24배차이)
  • 코드가 장황해지고 지저분해진다
  • 모든 클래스의 정보를 알기때문에 내부를 노출해서 추상화를 파괴시킨다.

--

--

Doyeon

Passionate iOS developer creating extraordinary apps. Innovative, elegant, and collaborative. Constantly pushing boundaries.Let's build the future together📱✨🚀