KSP를 만들어 봤어요.

6183 단어 Kotlinksptech
KSP를 만진 후 여러가지 고생으로 필기를 했다.
처음에 이루고 싶었던 일이 이루지 못한 결말도 있다.

KSP를 사용하는 모듈


build.gradle


plugins {
    id 'com.android.library'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'

    id "com.google.devtools.ksp" version "1.5.31-1.0.0"
}

dependencies {
    implementation project(":Wasabi")
    ksp project(":Wasabi")
}
이게 다야.
Wasabi 모듈은 KSP 처리라고 쓰여 있는 모듈입니다.

KSP 호스트 모듈


build.gradle


plugins {
    id 'org.jetbrains.kotlin.jvm'
    id "com.google.devtools.ksp" version "1.5.31-1.0.0"
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib"
    implementation "com.google.devtools.ksp:symbol-processing-api:1.5.31-1.0.0"
}
정말 이게 다야.
안드로이드랑 상관 없으니까 안드로이드계 정보도 안 썼어요

META-INF/services



모듈 내의 문서는 이렇게 구성되어 있다.
META-IN/서비스 아래에서 Provider와 Processor가 지정한 파일을 설정합니다.
※ 공식 홈페이지를 봐도 파일 이름이 달라 괴로운 점com.google.devtools.ksp.processing.SymbolProcessorProviderjavax.annotation.processing.Processor 서류 준비.
파일 내용이 각각 다르다
sobaya.lib.wasabi.WasabiProvider
sobaya.lib.wasabi.WasabiProcessor
.

Provider


package sobaya.lib.wasabi

import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider

class WasabiProvider : SymbolProcessorProvider {
    override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
        return WasabiProcessor(environment.codeGenerator, environment.logger)
    }
}
나는 단지 Processor의 실례를 너에게 돌려줄 뿐이다.

Processor


override fun process(resolver: Resolver): List<KSAnnotated> {
    if (invoked) {
        return emptyList()
    }

    val functions = ArrayList<String>()
    val viewModels = getViewModels(resolver)
    val states = getStates(resolver)

    states.forEach { (viewModelPath, fieldName) ->
        val viewModel = viewModels.find {viewModelPath.contains(it) }
        viewModel?.let {
            functions.add(makeFunction(viewModel, fieldName))
        }
    }

    val file = codeGenerator.createNewFile(
        Dependencies(false),
        "sobaya.wasabi",
        "StateExtensions"
    )

    file.write(functions.joinToString("\n").toByteArray())
    file.close()

    invoked = true
    return emptyList()
}
길기 때문에 우선 본편만 기재했다.functions에 KSP에 필요한 함수가 포함된 문자열입니다.
codeGenerator.createNewFile(
        Dependencies(false),
        "sobaya.wasabi",
        "StateExtensions"
    )
functions에 들어갈 문자열을 ↑ 파일에 씁니다.
이 예라면 sobaya.wasabi.StateExtensions.kt 파일에 기록될 것입니다.
이번에는 생략했지만 네 번째 인자에서 확장자를 지정하면 텍스트 파일을 만들 수 있습니다.

반에 설치된 Annotation으로부터 정보를 얻다


val viewModelSymbol = resolver.getSymbolsWithAnnotation("sobaya.lib.wasabi.ViewModel")

        viewModelSymbol.filterIsInstance<KSClassDeclaration>().forEach {
            viewModels.add("${it.packageName.asString()}.${it.simpleName.asString()}")
        }
getSymbolsWithAnnotation에 자제한 모조 정보를 전달하여 모조가 수여된 곳을 얻는다.filterIsInstance<KSClassDeclaration> 이번엔 반에 담아야 하니까 KSClass Declation으로 필터it.packageName.asString()의 패키지 이름it.simpleName.asString() 클래스 이름을 얻을 수 있습니다.

필드의 Annotation에서 정보 얻기


val stateSymbol = resolver.getSymbolsWithAnnotation("sobaya.lib.wasabi.State")

stateSymbol.filterIsInstance<KSPropertyDeclaration>().forEach { it ->
    it.annotations.forEach {
        val filePath = (it.parent?.location as FileLocation).filePath
        val file = File(filePath)
        val fieldName = it.parent.toString()
        states.add(file.path.replace("/", ".") to fieldName)
    }
}
getSymbolsWithAnnotation에서 초대 정보를 얻는 것은 통용된다.KSPropertyDeclaration 이번에는 변수의 정보를 원하기 때문에 여기서 필터를 합니다.
KSPropertyDeclaration.annotations 내용 확인(it.parent?.location as FileLocation).filePath에 어떤 파일이 적혀 있는지it.parent.toString()를 통해 변수 이름을 얻을 수 있습니다.
예제)
@Test
val test = Data()
인 경우 test틀을 만들 수도 있지만 이번에는 사용하지 않아서 필기를 잊어버렸어요.

최후



프로젝트를 ReBuild로 진행하면 지정한 파일이 임의로 생성됩니다.
이번에 ViewModel의 State 관리에서 데이터 클래스를 사용할 때
state.value = state.value.copy(list = it)
쓰기가 귀찮아서 편리한 기능을 하고 싶어요.
시간이 넉넉해서 실패했다.
하지만 구축할 때 기능을 추가하는 것이 재미있기 때문에 생각에 따라 꿈이 넓어진다.
↑ 코드 청소와 debug 설정 문제 해결
하고 싶은 일을 실현하는 소스 코드입니다.
https://github.com/sobaya-0141/Sample2109/pull/1

참고 자료


https://github.com/google/ksp
https://speakerdeck.com/star_zero/droidkaigi-2021
https://star-zero.medium.com/ksp코드로 생성 - 1c2f421aaa9

좋은 웹페이지 즐겨찾기