KotlinPoet usages

WindSekirun (wind.seo)·2022년 4월 26일
0

이 글은 기존 운영했던 WordPress 블로그인 PyxisPub: Development Life (pyxispub.uzuki.live) 에서 가져온 글 입니다. 모든 글을 가져오지는 않으며, 작성 시점과 현재 시점에는 차이가 많이 존재합니다.

작성 시점: 2018-03-16

먼저 이 글은 아래의 글을 참조로 하였다.

KotlinPoet を使って Android プロジェクトでコードジェネレーションする (KotlinPoet를 사용해 Android 프로젝트의 코드 제네레이션을 한다)

はじめて KotlinPoet を使ったときのメモ (처음 KotlinPoet를 사용했을 때의 메모)

문자열, Literal, 타입 출력

만약 아래의 코드를 작성하고 싶다고 해보자.

Log.d("TAG", "Something new!");

그러면, 아래의 코드를 사용할 수도 있다.

val tag = "TAG"
val message = "Something new!"

builder.addCode("android.util.Log.d(\\"$tag\\", \\"$message\\");")

아니면, 아래의 코드를 사용할 수도 있다.

val tag = "TAG"
val message = "Something new!"

builder.addStatement("%T.d(%S, %S)", ClassName.bestGuess("android.util", "Log"), tag, message);

당연히 후자가 마음에 든다.

이 처럼, %S, %L, %T 등을 이용하여 표현식을 작성할 수 있다.

  • %T: 타입에 대한 format, 주로 ClassName 객체를 반환한다. ClassName.bestGuess(packageName, simpleName) 로 해당 패키지 이름과 클래스 이름을 가진 클래스를 찾아낸다. 여기서는 android.util 클래스의 Log를 찾으라고 했으니, android.util.Log 가 검출된다. 그리고, 이 bestGuess로 찾아낸 타입들은 알아서 import문이 추가된다.
  • %S: 문자열에 대한 format, 해당 문자열에 quota를 더해서 출력한다.
  • %L: 리터럴에 대한 format, 해당 문자열을 그대로 출력한다.

Static by @JvmStatic

Static 를 하고자 하는 메서드의 생성 Spec(FunSpec) 에 .addAnnotation(JvmStatic::class) 를 추가하면 된다.

Property의 생성 및 초기화

val parameterName = "person"
val typeName = ClassName.bestGuess("pyxis.uzuki.live.demo", "Person);

PropertySpec.builder(parameterName, typeName, KModifier.PRIVATE).initializer("Person()").build()

builder 의 3번째 파라미터는 KModifier 의 가변 인자(vararg) 로, Modifier 를 여러 개 붙일 수 있다.

Property의 val/var (mutable)

val parameterName = "person"
val typeName = ClassName.bestGuess("pyxis.uzuki.live.demo", "Person);

PropertySpec.builder(parameterName, typeName, KModifier.PRIVATE).initializer("Person()").mutable(true).build()

간단하게 mutable(true) 만 추가해주면 된다.

Function의 파라미터

val parameterName = "person"
val typeName =ClassName.bestGuess("pyxis.uzuki.live.demo", "Person)

FunSpec.builder("apply")
   .addModifier(KModifier.PUBLIC)
   .addParameter(parameterName, typeName)

해당 FunSpec의 builder 에 addParameter 메서드를 사용하면 된다.

if 조건문

this.beginControlFlow("if ($variableName.length == 0)")
            .addCode(String.format("%s = %s;\\n", variableName, defValue))
            .endControlFlow()

중요한건 beginControlFlow 등은 중괄호만 생성해준다는 것이다. 따라서 if 나 for 는 저렇게 하드코딩 하거나 위의 %L, %S 등을 이용해 적절하게 표시해야 한다.

Primitive 처리

Int, Double 등을 처리할 때 Primitive 는 ClassName 로 처리할 수 없다는 오류를 발생시킬 수 있는데, 아래 메서드를 사용하면 된다.

val ANY = ClassName("kotlin", "Any")
val ARRAY = ClassName("kotlin", "Array")
val UNIT = Unit::class.asClassName()
val BOOLEAN = ClassName("kotlin", "Boolean")
val BYTE = ClassName("kotlin", "Byte")
val SHORT = ClassName("kotlin", "Short")
val INT = ClassName("kotlin", "Int")
val LONG = ClassName("kotlin", "Long")
val CHAR = ClassName("kotlin", "Char")
val FLOAT = ClassName("kotlin", "Float")
val DOUBLE = ClassName("kotlin", "Double")
val STRING = ClassName("kotlin", "String")

fun String.bestGuess(): TypeName {
    return when (this) {
        "int" -> INT
        "byte" -> BYTE
        "short" -> SHORT
        "long" -> LONG
        "char" -> CHAR
        "float" -> FLOAT
        "double" -> DOUBLE
        "String" -> STRING
        "java.lang.String" -> STRING
        "boolean" -> BOOLEAN
        "Unit" -> UNIT
        "Any" -> ANY
        else -> ClassName.bestGuess(this)
    }
}
profile
Android Developer @kakaobank

0개의 댓글