TIL

[TIL] KAPT, KSP [ 1 ] / Annotation Processor, 개념

정상호소인 2023. 10. 9. 23:59

-1- Annotation

  • Annotation이란 사전적 의미로는 주석의 의미지만 기존에 코드에서 사용하던 ' // ' 의 주석과는 다른 역할을 한다. 지난 글에서 Retrofit2을 통해 API 를 호출할 때 다음과 같은 코드를 사용했었다
  • 특정 데이터에 대한 추가적인 세부 사항을 제공하는 것이 주 목적이므로 Annotation은 실행중에 직접 동작하지 않고 컴파일러나 런타임 환경에서 해당 정보를 참조할 수 있도록 한다.
@Get
@Header
@Query
@JsonClass(generateAdapter = true)
  • 이러한 코드를 Annotation이라고 한다. Annotation은 *메타 데이터의 한 형태로 컴파일러가 이를 참조할 수 있도록 해준다.
    @GET("search")
    suspend fun searchChannel(
        @Query("key") key: String = Constants.API_KEY,
        @Query("part") part: String,
        @Query("maxResults") maxResults: Int,
        @Query("q") q: String,
        @Query("regionCode") regionCode: String,
        @Query("type") type: String,
    ): Response<ChannelResponse>

위와 같은 상황에서 @Get은 컴파일 시 Get 요청을 보낼 엔드포인트의 경로를 지정하는 메타 데이터의 형태로 참조 되며, @Query Annotation은 해당 매개변수가 쿼리 파라미터임을 나타내는 메타 데이터의 형태로 참조된다.

 

Annotation의 장점

  • 컴파일 타임 체크
    • 컴파일러가 Annotation에 관한 요소의 에러를 확인하여 오류를 발생시켜 프로그램의 안정성을 향상시킨다.
  • 컴파일 시 생성
    • 코드나 xml 파일 등을 컴파일 타임에 생성할 수 있도록 처리한다.
  • 그 외 다양한 기능 제공
    • 코드 문서화, 가독성 개선, 정적 분석, 리플렉션 지원, 메타 프로그래밍, 외부 도구를 활용한 유연한 작업 등 여러 장점을 제공한다.

 

 

메타 데이터?

  • 메타 데이터는 특정 데이터에 대한 추가적인 세부 사항을 제공하여 해당 데이터를 효율적으로 인식할 수 있도록 해주는 것으로 어떤 데이터의 구조화 된 정보를 분석, 분류하고 부가적 정보를 추가하기 위해 그 데이터 뒤에 함께 따라가는 정보를 말한다. 사진을 촬영할 경우 해당 사진 데이터의 촬영 시간, 어떤 카메라로 찍었는지, 촬영 위치가 별도로 저장되는데 해당 데이터들이 메타 데이터이다.
  • 특정 데이터에 대한 추가적인 세부 사항을 제공하는 것이 주 목적이므로 Annotation은 실행중에 직접 동작하지 않고 컴파일러나 런타임 환경에서 해당 정보를 참조할 수 있도록 한다.
  • 메타 데이터에 대한 개념 이해가 어려울 경우 문서 참조
 

메타데이터 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 2010년대에 메타데이터는 일반적으로 디지털 형태를 가리킨다. 그러나 1960~1970년대의 전통적인 카드 카탈로그들 또한 메타데이터의 한 예로 들 수 있으며, 이 카

ko.wikipedia.org

 

 

Annotation Processor ( Java Compiler )

  • Anntation Processor은 컴파일 시 Annotation을 처리하고, 추가적인 코드를 생성하거나 변형하는 기능으로 Java Compiler에 내장된 도구이다. AP는 컴파일 시 어떤 프로세서가 동작할지 결정할 때 프로세서를 찾는 ' Service Loader' 라는 기능의 도움을 받아야 한다.
  • Kotlin 의 경우 Java 바이트코드로 변환되어 JVM에서 실행됨으로 Kotlin 컴파일러의 실행 후 Java 컴파일러가 바이너리 파일인 *.class를 인식한다. 이때 컴파일러는 Kotlin과 Java에서 생성된 각 바이너리에 대해서 구별할 수 없다. 또한 Kotlin은 언어의 특성상 Processor가 생성한 선언을 참조할 수 없고, 바이너리에는 주석이 포함되지 않기 때문에 이를 해결하기 위해 KAPT를 사용한다.

 

KAPT  ( Kotlin Annotation Processing Tool )

  • KAPT는 위에서 설명한 것과 같이 Javac에서 제공하는 Annotation Processor를 통해 생성된 선언을 Kotlin 컴파일러가 인식하지 못하는 문제로 인해 만들어졌다.
  • KAPT는 kotlin 컴파일러의 일부로 동작하며 소스 코드와 함께 생성되는 바이너리 파일을 인식하여 Annotation 처리 결과를 적용한다 이를 통해 Java와 Kotlin 코드 간의 상호 운용성을 개선하고 Kotlin에서의 Annotation 호환이 가능하도록 한다.
KSP가 여러 라이브러리를 지원하며 안정화됨에 따라 현재는 유지 관리 모드가 되어서 Kotlin 의 버전에 맞게 버전 상태를 유지하고 있지만, 추가적인 기능 구현 계획은 없다고 한다. 
Stub을 생성하기 위해 컴파일 및 빌드 타임에 시간이 소요된다 - KSP로 대체

 

 

KAPT 적용 방법

build.gradle( module )
plugins {
    ... 
    id("org.jetbrains.kotlin.android")
    id("kotlin-kapt")
}
  • build.gradle에 kapt 플러그인을 설정해주면 적용된다.

 

 

KSP ( Kotlin Symbol Processing )

  • KAPT는 Kotlin 컴파일러와 함께 실행되며 소스 코드를 분석하고 Annotation Processor를 실행하는 작업을 수행하는데, 이 과정에서 소스 코드를 처리하는데 시간이 소요된다.
  • 이러한 문제를 해결하기 위해 KSP는 다음과 같은 방식을 통해 컴파일 시간을 효과적으로 줄인다.
    • 증분처리 
      • 변경된 부분만을 대상으로 Annotation Processing을 실행하므로 이전에 처리한 결과를 캐시하고, 변경된 부분에 대해서만 재처리하여 필요한 작업을 수행한다. 이는 전체 소스 코드가 아닌 변경 사항만 처리함으로 많은 양의 작업을 생략할 수 있다.
    • 병렬처리
      • KSP는 여러 스레드에서 동시에 Annotation Processing을 처리하므로 처리시간을 단축시킨다.
    • Symbol 기반
      • KSP는 Kotlin 컴파일러 내부의 Symbol 정보에 직접 접근하여 작업을 수행하는데, KAPT가 소스 코드를 분석하는 데 사용하는 AST( Abstract Syntax Tree ) 방식보다 효율적이다. Symbol은 컴파일러가 생성한 중간표현으로, 정적인 정보를 가지고 있어 Annotation에서 필요한 정보를 빠르게 접근할 수 있다.
    • Gradle 증분 컴파일 지원
      • Gradle 빌드 시스템의 증분 컴파일 기능과 함께 사용될 수 있으며 변경된 소스 코드만 재 컴파일되고, KSP도 변경된 부분만 처리하여 전체적인 빌드 시간을 단축시킨다.

 

KSP 적용 방법

build.gralde ( project )
plugins {

    id("org.jetbrains.kotlin.android") version "1.8.0" apply false
    id("com.google.devtools.ksp") version "1.8.0-1.0.9" apply false
    
}
  • Kotlin 버전과 일치하는 버전을 적용해주어야 한다. ( plugin 내부에서 kotlin.android version 확인할 수 있다 )

 

build.gradle ( module )
plugins {

    ...
    id("org.jetbrains.kotlin.android")
    id("com.google.devtools.ksp")
    
    ...
}
  • module 수준의 build.gradle의 plugin도 추가해주고 Sync 해주면 적용된다.

 


 

[오늘 복습한 내용]

1. Retrofit을 학습할 때 Annotation에 대해서 간단하게 학습하고 넘어갔었는데, Annotation에 대해서 추가로 학습... KSP를 처음 접했을 떈 Dagger hilt 등 라이브러리 사용 시 ksp가 불안정했었던 것 같은데 지금은 dagger Hilt도 정상적으로 지원한다고 하니 DI 를 학습할 때 KSP를 사용해봐야겠다

 

 


[오류,에러 등등]

1. 개념 공부 위주로 진행해서 에러는 없었는데, 메타 데이터 개념을 이해하기가 어려웠다. 개념만 보고 직접 예시를 만들어보려고 했으나 위키에 나오는 예시외에 적절한 예시를 찾기가 어려웠다

 


[느낀 점]

1. 개념 학습이 중요한 것 같다.

 

2. 직접 고민하는 시간을 더 늘리자

 

3. 앞으로 배울 게 아직 너무 많은 느낌인데 천천히 하자 

 

 


[Reference]

 

// KSP

https://kotlinlang.org/docs/ksp-overview.html#overview

 

//메타 데이터

https://ko.wikipedia.org/wiki/%EB%A9%94%ED%83%80%EB%8D%B0%EC%9D%B4%ED%84%B0

 

// Annotation 

https://androiddeepdive.github.io/Team-Blog/2021/07/21/2021-07-21%20Kotlin%20Symbol%20Processing%20Api%20Part%201/