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 }