【kapt】 처리 대상 클래스의 패키지를 지정하여 파일을 내보내는 【KotlinPoet】
13476 단어 KotlinPoetKotlinkapt
kapt
+ KotlinPoet
에서 처리 대상 클래스의 패키지를 지정하여 파일을 내보냅니다.하는 방법은 몇 가지 있습니다만, 이 기사에서는
ClassName
로부터 패키지명·클래스명의 정보를 취득해, ProcessingEnvironment
로부터 취득한 filer
를 지정해 내보내는 방법을 소개합니다.버전은 다음과 같습니다.
Kotlin
: 1.4.31
KotlinPoet
: 1.7.2
AutoCommon
: 0.11
AutoService
: 1.0-rc7
샘플 코드
어노테이션을 붙인 클래스에 대해서, 그 코드와 같은 패키지에 hello from ${クラス名}
(와)과 프린트 하는 코드를 생성하는 샘플입니다.
특히 중요한 것은 generateHelloWorld
함수입니다.
이하, 이쪽의 샘플 코드를 이용해 해설해 갑니다.
import com.google.auto.common.BasicAnnotationProcessor
import com.google.auto.service.AutoService
import com.google.common.collect.SetMultimap
import com.mapk.annotations.TargetAnnotation
import com.squareup.kotlinpoet.*
import javax.annotation.processing.Filer
import javax.annotation.processing.Processor
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
// 処理対象アノテーション
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class TargetAnnotation
@AutoService(Processor::class)
class Processor : BasicAnnotationProcessor() {
override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported()
override fun getSupportedOptions(): Set<String> = setOf()
override fun initSteps(): Iterable<ProcessingStep> {
return listOf(TempProcessingStep(processingEnv.filer))
}
}
class TempProcessingStep(private val filer: Filer) : BasicAnnotationProcessor.ProcessingStep {
override fun annotations() = setOf(TargetAnnotation::class.java)
override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>): Set<Element> {
annotations()
.flatMap { elementsByAnnotation[it] }
.forEach {
// 簡単のためクラスに付与する想定
if (it.kind == ElementKind.CLASS) generateHelloWorld(it as TypeElement)
}
return emptySet()
}
// ハローワールドを出力する関数
private fun generateHelloWorld(element: TypeElement) {
val className = element.asType().asTypeName() as ClassName
val funSpec = FunSpec.builder("helloWorld").apply {
addStatement("""println("hello from ${className.simpleName}")""")
}.build()
val file = FileSpec.builder(className.packageName, "HelloFrom${className.simpleName}")
.addFunction(funSpec)
.build()
file.writeTo(System.out) // デバッグ用にSystem.outにも出力
file.writeTo(filer) // ファイルへ出力
}
}
ClassName 얻기
처리 대상의 Element
가 TypeElement
이면, element.asType().asTypeName()
로 취득한 TypeName
를 ClassName
에 캐스트 할 수 있습니다.
ClassName 취득부private fun generateHelloWorld(element: TypeElement) {
val className = element.asType().asTypeName() as ClassName
이 ClassElement
로부터는 패키지명이나 클래스명을 간단하게 취득할 수 있습니다.
패키지명・파일명 설정부val file = FileSpec.builder(className.packageName, "HelloFrom${className.simpleName}")
보충
TypeMirror.asTypeName()
는 현재 Deprecated
되고 있어 , 「 kotlinpoet-metadata
를 사용해」라고 하는 취지의 경고가 나옵니다만 , 방법을 모르기 때문에 이 기사에서는 무시하고 있습니다.
이 문제는 아마 Kotlin
와 Java
로 표현이 다른 형( Int
이나 String
)에 대해서 일어나는 것으로, 이번 취급하는 범위에서는 문제 없다고 생각하고 있습니다.
출력 대상 지정
출력처는 ProcessingEnvironment
로부터 취득한 Filer
를 지정합니다.ProcessingEnvironment
는 AbstractProcessor
( BasicAnnotationProcessor
의 부모 클래스)를 상속하는 경우 processingEnv
필드에서 가져올 수 있습니다.
파일에 내보내기file.writeTo(filer) // ファイルへ出力
이것을 지정했을 경우, 이용측에서 특별히 지정이 없으면 ${モジュールのroot}/build/generated/source/kapt/main/${指定したパッケージへのパス}
가 출력처가 됩니다.
실행 결과
com.mapk.test
라는 패키지에 다음과 같은 처리 대상을 준비해 실행한 결과를 나타냅니다.
package com.mapk.test
import com.mapk.annotations.TargetAnnotation
@TargetAnnotation
object TestTarget
fun main() { helloWorld() }
빌드 로그
file.writeTo(System.out)
에 의해, 이하와 같이 결과를 확인할 수 있습니다.
# 略
> Task :test:processResources NO-SOURCE
> Task :test:kaptKotlin
package com.mapk.test
import kotlin.Unit
public fun helloWorld(): Unit {
println("hello from TestTarget")
}
> Task :test:compileKotlin
# 略
생성된 코드
다음과 같이 코드가 생성됩니다.
제대로 패키지도 지정되어 있는 것을 알 수 있습니다.
생성된 코드package com.mapk.test
import kotlin.Unit
public fun helloWorld(): Unit {
println("hello from TestTarget")
}
참고로 한 내용
import com.google.auto.common.BasicAnnotationProcessor
import com.google.auto.service.AutoService
import com.google.common.collect.SetMultimap
import com.mapk.annotations.TargetAnnotation
import com.squareup.kotlinpoet.*
import javax.annotation.processing.Filer
import javax.annotation.processing.Processor
import javax.lang.model.SourceVersion
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
// 処理対象アノテーション
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class TargetAnnotation
@AutoService(Processor::class)
class Processor : BasicAnnotationProcessor() {
override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported()
override fun getSupportedOptions(): Set<String> = setOf()
override fun initSteps(): Iterable<ProcessingStep> {
return listOf(TempProcessingStep(processingEnv.filer))
}
}
class TempProcessingStep(private val filer: Filer) : BasicAnnotationProcessor.ProcessingStep {
override fun annotations() = setOf(TargetAnnotation::class.java)
override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>): Set<Element> {
annotations()
.flatMap { elementsByAnnotation[it] }
.forEach {
// 簡単のためクラスに付与する想定
if (it.kind == ElementKind.CLASS) generateHelloWorld(it as TypeElement)
}
return emptySet()
}
// ハローワールドを出力する関数
private fun generateHelloWorld(element: TypeElement) {
val className = element.asType().asTypeName() as ClassName
val funSpec = FunSpec.builder("helloWorld").apply {
addStatement("""println("hello from ${className.simpleName}")""")
}.build()
val file = FileSpec.builder(className.packageName, "HelloFrom${className.simpleName}")
.addFunction(funSpec)
.build()
file.writeTo(System.out) // デバッグ用にSystem.outにも出力
file.writeTo(filer) // ファイルへ出力
}
}
private fun generateHelloWorld(element: TypeElement) {
val className = element.asType().asTypeName() as ClassName
val file = FileSpec.builder(className.packageName, "HelloFrom${className.simpleName}")
file.writeTo(filer) // ファイルへ出力
com.mapk.test
라는 패키지에 다음과 같은 처리 대상을 준비해 실행한 결과를 나타냅니다.package com.mapk.test
import com.mapk.annotations.TargetAnnotation
@TargetAnnotation
object TestTarget
fun main() { helloWorld() }
빌드 로그
file.writeTo(System.out)
에 의해, 이하와 같이 결과를 확인할 수 있습니다.# 略
> Task :test:processResources NO-SOURCE
> Task :test:kaptKotlin
package com.mapk.test
import kotlin.Unit
public fun helloWorld(): Unit {
println("hello from TestTarget")
}
> Task :test:compileKotlin
# 略
생성된 코드
다음과 같이 코드가 생성됩니다.
제대로 패키지도 지정되어 있는 것을 알 수 있습니다.
생성된 코드
package com.mapk.test
import kotlin.Unit
public fun helloWorld(): Unit {
println("hello from TestTarget")
}
참고로 한 내용
Reference
이 문제에 관하여(【kapt】 처리 대상 클래스의 패키지를 지정하여 파일을 내보내는 【KotlinPoet】), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/wrongwrong/items/04d0c78953f0c0399df3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)