kapt 컴파일러 플러그인

kapt 컴파일러 플러그인

kapt 컴파일러 플러그인을 쓰면 Kotlin에서 기존 Java 어노테이션 프로세서를 사용할 수 있어요. Maven과 Gradle 모두에서 동작하죠. kapt는 Kotlin 소스 코드에서 스텁(stub) 파일을 생성한 다음, 그 스텁에 대해 Java 어노테이션 프로세서를 실행해요.

덕분에 MapStructData Binding 같은 라이브러리를 위한 Java 기반 어노테이션 처리를 Kotlin 프로젝트에서 쓸 수 있어요.

경고: kapt는 IntelliJ 빌드 시스템에서는 지원되지 않아요. IntelliJ IDEA에서 어노테이션 처리를 다시 실행하려면, Maven 도구 창에서 빌드를 시작해야 해요.

플러그인 설정하기

kapt 플러그인은 Gradle, Maven에서 구성하거나 명령줄에서 사용할 수 있어요.

Gradle

Gradle에서 kapt를 사용하려면 다음 단계를 따라 해요.

  • 빌드 스크립트 파일 build.gradle(.kts)kapt Gradle 플러그인을 적용해요.
plugins {
    kotlin("kapt") version "2.4.20"
}
plugins {
    id "org.jetbrains.kotlin.kapt" version "2.4.20"
}
  • dependencies {} 블록에서 kapt 구성을 사용해 해당 의존성을 추가해요.
dependencies {
    kapt("groupId:artifactId:version")
}
dependencies {
    kapt 'groupId:artifactId:version'
}
  • 이전에 어노테이션 프로세서에 Android 지원을 사용했다면, annotationProcessor 구성 사용을 kapt로 바꿔요. 프로젝트에 Java 클래스가 있으면 kapt 플러그인이 그 클래스도 함께 처리해요.

androidTest 또는 test 소스에 어노테이션 프로세서를 사용한다면, 해당 kapt 구성은 각각 kaptAndroidTestkaptTest라는 이름이에요. kaptAndroidTestkaptTestkapt를 확장하므로, kapt 의존성을 제공하면 그 의존성이 프로덕션 소스와 테스트 모두에서 사용 가능해져요.

Maven

kapt는 설정을 단순화하는 <extensions> 옵션이나, kapt 실행을 완전히 제어할 수 있는 수동 구성으로 설정할 수 있어요.

자동 구성

Kotlin Maven 플러그인에서 <extensions> 옵션을 활성화하면 kapt 구성을 단순화할 수 있어요. 이 경우 goal이나 소스 디렉터리를 지정한 kapt의 <execution> 섹션을 직접 설정하지 않아도 돼요.

kapt를 자동으로 구성하려면, pom.xml 빌드 파일의 kotlin-maven-plugin에서 <extensions> 옵션을 true로 설정하세요.

<plugin>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-maven-plugin</artifactId>
    <version>${kotlin.version}</version>
    <extensions>true</extensions>
    <configuration>
        <annotationProcessorPaths>
            <!-- Specify your annotation processors here -->
            <annotationProcessorPath>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.6.3</version>
            </annotationProcessorPath>
        </annotationProcessorPaths>
    </configuration>
</plugin>

<extensions> 옵션에 대한 자세한 내용은 자동 구성 문서를 참고하세요.

수동 구성

Kotlin Maven 프로젝트에서 kapt를 수동으로 설정하려면, compile 실행 앞에 kotlin-maven-pluginkapt goal 실행을 추가해요.

<execution>
    <id>kapt</id>
    <goals>
        <goal>kapt</goal>
    </goals>
    <configuration>
        <sourceDirs>
            <sourceDir>src/main/kotlin</sourceDir>
            <sourceDir>src/main/java</sourceDir>
        </sourceDirs>
        <annotationProcessorPaths>
            <!-- Specify your annotation processors here -->
            <annotationProcessorPath>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.6.3</version>
            </annotationProcessorPath>
        </annotationProcessorPaths>
    </configuration>
</execution>

어노테이션 처리 모드를 구성하려면, <configuration> 블록에서 aptMode 옵션을 설정해요. 예를 들어 이렇게요.

<configuration>
   ...
   <aptMode>stubs</aptMode>
</configuration>

CLI

kapt는 Kotlin 컴파일러 바이너리 배포판에 독립 실행형 CLI 도구로 포함돼 있어요.

명령줄에서 kapt를 실행하려면 다음을 사용해요.

kapt <options> <source files>

예를 들어 이렇게요.

kapt -Kapt-mode=stubsAndApt \
  -Kapt-sources=build/kapt/sources \
  -Kapt-classes=build/kapt/classes \
  -Kapt-stubs=build/kapt/stubs \
  -Kapt-classpath=lib/ap.jar \
  -Kapt-classpath=lib/anotherAp.jar \
  src/main/kotlin

어노테이션 프로세서 구성하기

kapt는 어노테이션 프로세서를 어떻게 발견하고 구성하고 실행할지 제어하는 옵션을 제공해요. 프로세서 클래스패스 관리, 공유 구성에서 프로세서 상속, javac 전용 프로세서 유지 같은 것들이죠.

어노테이션 프로세서에 옵션을 전달하거나 javac에 옵션을 전달하는 것 같은 더 많은 구성 옵션은 어노테이션 프로세서 구성을 참고하세요.

프로세서 클래스패스와 발견 구성하기

kapt의 프로세서 경로에 포함되지 않은 어노테이션 프로세서의 발견을 비활성화할 수 있어요. 이러면 불필요한 어노테이션 프로세서를 컴파일 클래스패스에서 제외할 수 있죠.

Gradle

Gradle은 컴파일 회피(compile avoidance)를 사용해서 프로젝트를 다시 빌드할 때 어노테이션 처리를 건너뛰어요. 덕분에 kapt의 증분 빌드 시간이 개선되죠. 특히 다음 경우에 어노테이션 처리를 건너뜁니다.

  • 프로젝트의 소스 파일이 변경되지 않은 경우
  • 의존성 변경이 ABI 호환이 되는 경우(예: 함수 본문만 바뀐 경우)

하지만 컴파일 클래스패스에서 발견된 어노테이션 프로세서에는 컴파일 회피를 사용할 수 없어요. 프로세서 내부 구현이 바뀌면 프로세서의 ABI가 그대로여도 어노테이션 처리 작업을 다시 실행해야 하기 때문이죠.

그래서 컴파일 클래스패스의 어노테이션 프로세서를 사용하는 것은 권장하지 않아요. kapt 처리에서 이 프로세서들을 제외하려면, gradle.properties 파일에 kapt.include.compile.classpath 속성을 추가하세요.

# gradle.properties
kapt.include.compile.classpath=false

옵션이 false로 설정되면, 프로세서 경로(kapt* 구성)에 포함되지 않은 어노테이션 프로세서 의존성은 kapt 처리에서 제외돼요.

Maven

kapt의 프로세서 경로에 포함되지 않은 어노테이션 프로세서를 제외하려면, kapt 플러그인의 <execution> 섹션에서 includeCompileClasspath 옵션을 false로 설정해요.

<execution>
    <id>kapt</id>
    <goals>
        <goal>kapt</goal>
    </goals>
    <configuration>
        <includeCompileClasspath>false</includeCompileClasspath>
        <sourceDirs>...</sourceDirs>
        <annotationProcessorPaths>...</annotationProcessorPaths>
    </configuration>
</execution>

또는 pom.xml<properties> 섹션에서 kapt.include.compile.classpath 속성을 쓸 수도 있어요.

<properties>
    <kapt.include.compile.classpath>false</kapt.include.compile.classpath>
</properties>

옵션이 false로 설정되면, <annotationProcessorPaths> 섹션에 포함되지 않은 어노테이션 프로세서는 kapt 처리에서 제외돼요.

includeCompileClasspath 옵션을 설정하지 않았는데 kapt가 프로세서 경로에 명시적으로 정의되지 않은 어노테이션 프로세서를 컴파일 클래스패스에서 발견하면, 사용 중단(deprecation) 경고가 표시돼요.

[WARNING] Annotation processors discovery from compile classpath is deprecated.
Set 'kapt.include.compile.classpath=false' to disable discovery.

팁: kapt 클래스패스에 포함되지 않은 어노테이션 프로세서의 목록을 보려면, --info 로그 레벨 옵션으로 빌드를 실행해 보세요.

상위 구성에서 어노테이션 프로세서 상속하기

별도의 Gradle 구성에 공통 어노테이션 프로세서 세트를 상위 구성(superconfiguration)으로 정의하고, 서브프로젝트의 kapt 전용 구성에서 이를 확장할 수 있어요.

예를 들어 MapStruct를 사용하는 서브프로젝트라면, build.gradle(.kts) 파일에서 다음 구성을 사용해요.

val commonAnnotationProcessors by configurations.creating
configurations.named("kapt") { extendsFrom(commonAnnotationProcessors) }

dependencies {
    implementation("org.mapstruct:mapstruct:1.6.3")
    commonAnnotationProcessors("org.mapstruct:mapstruct-processor:1.6.3")
}

이 예제에서 commonAnnotationProcessors Gradle 구성은 모든 프로젝트에 사용하려는 어노테이션 처리를 위한 공통 상위 구성이에요. extendsFrom() 메서드를 사용해서 commonAnnotationProcessors를 상위 구성으로 추가했죠. kapt는 commonAnnotationProcessors Gradle 구성이 MapStruct 어노테이션 프로세서에 대한 의존성을 가진다는 것을 알게 돼요. 그래서 kapt는 어노테이션 처리를 위해 자기 구성에 MapStruct 어노테이션 프로세서를 포함해요.

Java 컴파일러의 어노테이션 프로세서 유지하기

기본적으로 kapt는 모든 어노테이션 프로세서를 실행하고 javac의 어노테이션 처리는 비활성화해요. 하지만 Lombok 같은 일부 어노테이션 프로세서는 javac이 실행해야 할 수도 있어요.

Gradle 빌드 파일에서는 keepJavacAnnotationProcessors 옵션을 사용해요.

kapt {
    keepJavacAnnotationProcessors = true
}

Maven을 쓴다면 플러그인을 명시적으로 구성해야 해요. Lombok 컴파일러 플러그인 설정 예시를 참고하세요.

kapt 빌드 최적화하기

kapt는 어노테이션 처리 시간을 줄이는 여러 Gradle 전용 전략을 제공해요. 작업을 병렬로 실행하거나, 빌드 캐시를 활용하거나, 프로세서 클래스로더를 캐시하거나, 증분 어노테이션 처리를 사용하는 것들이죠.

오류 타입 수정, 스텁 메타데이터 제거, 컴파일 클래스패스 스캔처럼 빌드 동작에 영향을 주는 더 많은 옵션은 동작 옵션을 참고하세요.

kapt 작업을 병렬로 실행하기

kapt는 Gradle Worker API를 사용해서 어노테이션 처리 작업을 실행해요. Worker API를 쓰면 Gradle이 단일 프로젝트의 독립적인 어노테이션 처리 작업을 병렬로 실행할 수 있고, 경우에 따라 실행 시간이 크게 줄어들어요.

Kotlin Gradle 플러그인에서 커스텀 JDK 버전을 설정했다면, kapt 작업 워커는 processIsolation() 모드만 사용해요.

kapt 워커 프로세스에 추가 JVM 인자를 제공하고 싶다면, KaptWithoutKotlincTaskkaptProcessJvmArgs 입력을 사용해요.

tasks.withType<org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask>()
    .configureEach {
        kaptProcessJvmArgs.add("-Xmx512m")
    }
tasks.withType(org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask.class)
    .configureEach {
        kaptProcessJvmArgs.add('-Xmx512m')
    }

Gradle 빌드 캐시 안전하게 사용하기

Gradle은 기본적으로 kapt 어노테이션 처리 작업을 캐시해요. 하지만 어노테이션 프로세서는 임의의 코드를 실행할 수 있어요. 그래서 작업 입력이 출력으로 불필요하게 변형되거나, Gradle이 추적하지 않는 파일에 접근·수정하는 일이 생길 수 있죠.

빌드에 사용된 어노테이션 프로세서를 제대로 캐시할 수 없을 때는, 캐싱을 비활성화해서 kapt 작업의 오탐(false-positive) 히트를 막을 수 있어요. 이렇게 하려면 빌드 스크립트에서 useBuildCache 속성을 사용해요.

kapt {
    useBuildCache = false
}

어노테이션 프로세서 클래스로더 캐시하기

어노테이션 프로세서의 클래스로더를 캐시하면, Gradle 작업을 연속으로 많이 실행할 때 kapt가 더 빨라져요.

이 기능을 활성화하려면 gradle.properties 파일에서 다음 속성들을 사용해요.

# gradle.properties
#
# Any positive value enables caching
# Use the same value as the number of modules that use kapt
kapt.classloaders.cache.size=5

# Disable for caching to work
kapt.include.compile.classpath=false

어노테이션 프로세서 캐싱에 문제가 생기면, 그 프로세서들의 캐싱을 비활성화해요.

# Specify annotation processors' full names to disable caching for them
kapt.classloaders.cache.disableForProcessors=[annotation processors full names]

참고: 이 기능에서 문제가 생기면 YouTrack에 피드백을 남겨 주시면 감사하겠어요.

증분 어노테이션 처리 사용하기

Gradle에서 kapt는 기본적으로 증분 어노테이션 처리를 지원해서, 변경된 파일만 다시 처리해요.

현재 증분 어노테이션 처리는 다음 조건이 모두 충족될 때만 동작해요.

  • 증분 컴파일이 활성화된 경우
  • 빌드의 모든 어노테이션 프로세서가 증분 방식인 경우

증분 어노테이션 처리를 비활성화하려면 gradle.properties 파일에 이 줄을 추가하세요.

kapt.incremental.apt=false

참고: 현재 kapt의 증분 어노테이션 처리는 Maven이나 CLI에서는 지원되지 않아요.

성능 분석하기

kapt는 어노테이션 처리 성능을 이해하도록 돕는 내장 진단 기능을 제공해요. 프로세서별 실행 시간 보고서, 사용하지 않는 프로세서를 식별하는 생성 파일 수 같은 것들이죠.

증분 처리 디버깅을 위한 파일 읽기 기록이나 메모리 누수 감지 같은 더 많은 진단 옵션은 진단 및 통계 옵션을 참고하세요.

어노테이션 프로세서 성능 측정하기

어노테이션 프로세서 실행에 대한 성능 통계를 얻으려면 showProcessorStats 옵션을 사용해요. 출력 예시:

Kapt Annotation Processing performance report:
com.example.processor.TestingProcessor: total: 133 ms, init: 36 ms, 2 round(s): 97 ms, 0 ms
com.example.processor.AnotherProcessor: total: 100 ms, init: 6 ms, 1 round(s): 93 ms

이 보고서는 dumpProcessorStats 옵션으로 파일에 덤프할 수 있어요. 예를 들어, 다음 CLI 명령은 kapt를 실행하고 통계를 ap-perf-report.file 파일에 덤프해요.

kapt -Kapt-mode=stubsAndApt \
  -Kapt-classpath=processor/build/libs/processor.jar \
  -Kapt-dump-processor-stats=ap-perf-report.file \
  sample/src/main/

생성된 파일 수 추적하기

kapt 플러그인은 각 어노테이션 프로세서가 생성한 파일 수에 대한 통계를 보고할 수 있어요.

이를 통해 빌드에 사용되지 않는 어노테이션 프로세서가 포함됐는지 추적하는 데 도움이 돼요. 생성된 보고서를 사용해서 불필요한 어노테이션 프로세서를 유발하는 모듈을 찾고, 그 모듈을 피하도록 업데이트할 수 있어요.

통계 보고를 활성화하려면:

  • Gradle 빌드 파일에서 showProcessorStats 옵션을 true로 설정해요.
// build.gradle(.kts)
kapt {
    showProcessorStats = true
}
  • gradle.properties 파일에서 verbose 컴파일러 옵션을 true로 설정해요.
# gradle.properties
kapt.verbose=true

통계는 info 레벨의 로그에 나타나요. Annotation processor stats: 줄 다음에 각 어노테이션 프로세서의 실행 시간 통계가 나오고, 그 뒤에 Generated files report: 줄 다음에 각 프로세서가 생성한 파일 수 통계가 이어져요. 예를 들어 이렇게요.

[INFO] Annotation processor stats:
[INFO] org.mapstruct.ap.MappingProcessor: total: 290 ms, init: 1 ms, 3 round(s): 289 ms, 0 ms, 0 ms
[INFO] Generated files report:
[INFO] org.mapstruct.ap.MappingProcessor: total sources: 2, sources per round: 2, 0, 0

참고: 현재 showProcessorStatsverbose 컴파일러 옵션으로 생성 파일 수를 추적하는 것은 Maven이나 CLI에서는 지원되지 않아요.

Kotlin 소스 생성하기

kapt는 Kotlin 소스를 생성할 수 있어요. 그렇게 하려면 processingEnv.options["kapt.kotlin.generated"]를 사용해서 생성된 Kotlin 소스 파일을 지정된 디렉터리에 작성해요. 그러면 그 Kotlin 소스 파일들이 메인 소스와 함께 컴파일돼요.

참고: kapt는 생성된 Kotlin 파일에 대한 다중 라운드 어노테이션 처리를 지원하지 않아요.

컴파일러 옵션

어노테이션 프로세서 구성

옵션 설명 설정 방법
aptMode kapt 워크플로 단계의 실행을 제어해요.
- stubsAndApt — 스텁을 생성하고 어노테이션 처리를 실행(기본값)
- stubs — Kotlin에서 Java 스텁만 생성
- apt — 어노테이션 프로세서만 실행(스텁이 이미 있다고 가정)
Gradle: 직접 사용 불가; Gradle은 스텁과 apt를 별도 작업으로 실행함
Maven: `<aptMode>stubsAndApt</aptMode>`
CLI: -Kapt-mode=stubsAndApt
classpath 어노테이션 프로세서가 발견되는 클래스패스 항목. Gradle: dependencies { kapt("com.example:processor:1.0") }
Maven: `<annotationProcessorPaths>`
CLI: -Kapt-classpath=lib/my-processor.jar
processors 발견(discovery)을 우회해서 실행할 프로세서들의 쉼표로 구분된 완전한 클래스 이름. Gradle: kapt { annotationProcessor("com.example.MyProcessor") }
Maven: `<annotationProcessors>`
CLI: -Kapt-processors=com.example.MyProcessor
apOption 어노테이션 프로세서에 전달되는 키-값 옵션. Gradle: kapt { arguments { arg("room.schemaLocation", "$projectDir/schemas") } }
Maven: `<annotationProcessorArgs>`
CLI: -Kapt-options:room.schemaLocation=/schemas
javacOption Java 컴파일러에 전달되는 키-값 옵션. Gradle: kapt { javacOptions { option("-source", "11") } }
Maven: `<javacOptions>`
CLI: -Kapt-javac-option:-source=11
processIncrementally 증분 어노테이션 처리를 활성화해서, 변경에 영향을 받은 파일만 다시 처리해요. Gradle: kapt.incremental.apt=true (gradle.properties)
Maven: 현재 지원되지 않음
CLI: 현재 지원되지 않음

출력 디렉터리 옵션

옵션 설명 설정 방법
sources 어노테이션 프로세서가 .java 소스 파일을 생성하는 디렉터리. Gradle: build/generated/source/kapt/main으로 자동 설정됨
Maven: target/generated-sources/kapt/으로 자동 설정됨
CLI: -Kapt-sources=build/kapt/sources
classes 생성된 소스에서 컴파일된 .class 파일 디렉터리. Gradle: 자동 관리됨
Maven: 자동 관리됨
CLI: -Kapt-classes=build/kapt/classes
stubs Kotlin 소스에서 생성된 Java 스텁 파일 디렉터리. 어노테이션 프로세서의 입력으로 사용돼요. Gradle: 자동 관리됨
Maven: 자동 관리됨
CLI: -Kapt-stubs=build/kapt/stubs
incrementalData 증분 빌드를 위한 상태를 저장해요. Gradle: 자동 관리됨
Maven: 현재 지원되지 않음
CLI: 현재 지원되지 않음

동작 옵션

옵션 설명 설정 방법
correctErrorTypes 기본적으로 kapt는 알 수 없는 모든 타입(생성된 클래스의 타입 포함)을 NonExistentClass로 바꿔요. 스텁에서 오류 타입 추론(error type interference)을 활성화하면, 해결되지 않은 오류 타입을 생성된 소스의 타입으로 대체할 수 있어요. 기본값 false. Gradle: kapt { correctErrorTypes = true }
Maven: `<correctErrorTypes>true</correctErrorTypes>`
CLI: -Kapt-correct-error-types=true
dumpDefaultParameterValues 생성된 스텁에서 기본 파라미터 초기화식을 필드 값으로 포함해요. 기본값 false. Gradle: kapt { dumpDefaultParameterValues = true }
Maven: 사용 불가
CLI: -Kapt-dump-default-parameter-values=true
mapDiagnosticLocations 스텁 파일의 오류 메시지를 원래 Kotlin 소스 위치로 매핑해요. 기본값 false. Gradle: kapt { mapDiagnosticLocations = true }
Maven: `<mapDiagnosticLocations>true</mapDiagnosticLocations>`
CLI: -Kapt-map-diagnostic-locations=true
strict 스텁 생성 비호환성을 경고 대신 오류로 바꿔요. 기본값 false. Gradle: kapt { strictMode = true }
Maven: 사용 불가
CLI: -Kapt-strict=true
stripMetadata 생성된 스텁에서 @kotlin.Metadata 어노테이션을 제거해서, 스텁 크기를 줄이고 프로세서에서 Kotlin 관련 정보를 숨겨요. 기본값 false. Gradle: kapt { stripMetadata = true }
Maven: 사용 불가
CLI: -Kapt-strip-metadata=true
verbose 상세(verbose) kapt 로깅을 활성화해요. 기본값 false. Gradle: kapt.verbose=true (gradle.properties)
Maven: 현재 지원되지 않음
CLI: 현재 지원되지 않음
infoAsWarnings info 레벨 kapt 메시지를 경고로 승격해요. 기본값 false. Gradle: 직접 사용 불가
Maven: 현재 지원되지 않음
CLI: 현재 지원되지 않음
includeCompileClasspath 컴파일 클래스패스에서 어노테이션 프로세서를 스캔해요. 재현성을 위해 false로 설정해요. 기본값 true. Gradle: kapt { includeCompileClasspath = false }
Maven: `<includeCompileClasspath>false</includeCompileClasspath>`
CLI: 현재 지원되지 않음

진단 및 통계 옵션

옵션 설명 설정 방법
showProcessorStats 프로세서별 실행 시간을 stdout에 출력해요. Gradle: kapt { showProcessorStats = true }
Maven: 사용 불가
CLI: -Kapt-show-processor-stats=true
dumpProcessorStats 프로세서 타이밍 통계를 파일에 기록해요. Gradle: 사용 불가
Maven: 사용 불가
CLI: -Kapt-dump-processor-stats=build/kapt-stats.txt
dumpFileReadHistory 프로세서가 읽은 파일 목록을 파일에 기록해요. 증분 어노테이션 프로세서 디버깅에 유용해요. Gradle: 사용 불가
Maven: 사용 불가
CLI: -Kapt-dump-file-read-history=build/kapt-reads.txt
detectMemoryLeaks 메모리 누수 감지 모드: none, default, 또는 paranoid. Gradle: kapt { detectMemoryLeaks = "paranoid" }
Maven: 현재 지원되지 않음
CLI: 현재 지원되지 않음

다음은 무엇?