• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 import com.example.annotation.Builder
2 import com.squareup.javapoet.*
3 import javax.annotation.processing.AbstractProcessor
4 import javax.annotation.processing.RoundEnvironment
5 import javax.lang.model.SourceVersion
6 import javax.lang.model.element.ExecutableElement
7 import javax.lang.model.element.Modifier
8 import javax.lang.model.element.PackageElement
9 import javax.lang.model.element.TypeElement
10 
11 class JavaBuilderProcessor : AbstractProcessor() {
12 
getSupportedSourceVersionnull13     override fun getSupportedSourceVersion(): SourceVersion {
14         return SourceVersion.latestSupported()
15     }
getSupportedAnnotationTypesnull16     override fun getSupportedAnnotationTypes(): MutableSet<String> {
17         return mutableSetOf("com.example.annotation.Builder")
18     }
19 
processTypenull20     private fun processType(typeElement: TypeElement) {
21         val typeSpecBuilder = TypeSpec.classBuilder("${typeElement.simpleName}Builder")
22         val constructor = typeElement.enclosedElements.filterIsInstance<ExecutableElement>()
23                 .filter { it.simpleName.toString() == "<init>" }
24                 .first()
25 
26         constructor.parameters.forEach {
27             typeSpecBuilder.addField(ClassName.get(it.asType()), it.simpleName.toString(), Modifier.PRIVATE)
28             val parameterSpec = ParameterSpec.builder(ClassName.get(it.asType()), it.simpleName.toString()).build()
29             typeSpecBuilder.addMethod(
30                     MethodSpec.methodBuilder("with${it.simpleName.toString().replaceFirstChar { it.uppercase() } }")
31                             .addParameter(parameterSpec)
32                             .addModifiers(Modifier.PUBLIC)
33                             .addStatement("this.\$N = \$N", it.simpleName, it.simpleName)
34                             .addStatement("return this")
35                             .returns(ClassName.bestGuess("${typeElement.qualifiedName}Builder"))
36                             .build()
37             )
38         }
39         val statements = constructor.parameters.map { it.simpleName.toString() }.joinToString(", ")
40         typeSpecBuilder.addMethod(
41                 MethodSpec.methodBuilder("build")
42                         .addModifiers(Modifier.PUBLIC)
43                         .returns(ClassName.get(typeElement.asType()))
44                         .addStatement("return new ${typeElement.simpleName}($statements)")
45                         .build()
46         )
47         val javaFileBuilder = JavaFile.builder((typeElement.enclosingElement as PackageElement).qualifiedName.toString(), typeSpecBuilder.build())
48         javaFileBuilder.skipJavaLangImports(true).build().writeTo(processingEnv.filer)
49     }
50 
processnull51     override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
52         val elements = roundEnv!!.getElementsAnnotatedWith(Builder::class.java)
53         elements.filterIsInstance<TypeElement>()
54                 .map { processType(it) }
55         return true
56     }
57 
58 }