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.SymbolProcessorProvider
및javax.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 설정 문제 해결
하고 싶은 일을 실현하는 소스 코드입니다.
참고 자료
Reference
이 문제에 관하여(KSP를 만들어 봤어요.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/sobya/articles/0b9c9a510697b4텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)