Search

@AutoProcessor, javapoet, Annotation processor 결합 사용 가개발

해당 @AutoProcessor tutorials에 javapoet를 사용한 방식으로 변경해서 테스트 개발

사용자

1.
pom.xml
2.
main code
3.
dto code
4.
generated code
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>auto-service</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>annotation-processing</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
XML
복사
public class Test { public static void main(String[] args) { Model m = new ModelBuilder() .setIntValue(1) .build(); System.out.println(m.getIntValue()); } } ... import org.example.BuilderProperty; public class Model { private int intValue; public int getIntValue() { return this.intValue; } @BuilderProperty public void setIntValue(int intValue) { this.intValue = intValue; } }
Java
복사
테스트
생성 확인

auto-processor

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>annotation-processing</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <auto-service.version>1.0-rc2</auto-service.version> </properties> <dependencies> <dependency> <groupId>com.squareup</groupId> <artifactId>javapoet</artifactId> <version>1.13.0</version> </dependency> <dependency> <groupId>com.google.auto.service</groupId> <artifactId>auto-service</artifactId> <version>${auto-service.version}</version> <scope>provided</scope> </dependency> </dependencies> </project>
XML
복사
package org.example; import com.google.auto.service.AutoService; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; import javax.annotation.processing.*; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.IOException; import java.io.Writer; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @SupportedAnnotationTypes("org.example.BuilderProperty") @SupportedSourceVersion(SourceVersion.RELEASE_8) @AutoService(Processor.class) public class BuilderProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (TypeElement annotation : annotations) { Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation); Map<Boolean, List<Element>> annotatedMethods = annotatedElements.stream().collect(Collectors.partitioningBy(element -> ((ExecutableType) element.asType()).getParameterTypes().size() == 1 && element.getSimpleName().toString().startsWith("set"))); List<Element> setters = annotatedMethods.get(true); List<Element> otherMethods = annotatedMethods.get(false); otherMethods.forEach(element -> processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@BuilderProperty must be applied to a setXxx method with a single argument", element)); if (setters.isEmpty()) { continue; } String className = ((TypeElement) setters.get(0).getEnclosingElement()).getQualifiedName().toString(); Map<String, TypeMirror> setterMap = setters.stream() .collect(Collectors.toMap(setter -> setter.getSimpleName().toString(), setter -> ((ExecutableType) setter.asType()).getParameterTypes().get(0))); try { writeBuilderFile(className, setterMap); } catch (IOException e) { e.printStackTrace(); } } return true; } private void writeBuilderFile(String className, Map<String, TypeMirror> setterMap) throws IOException { String packageName = ""; int lastDot = className.lastIndexOf('.'); if (lastDot > 0) { packageName = className.substring(0, lastDot); } String simpleClassName = className.substring(lastDot + 1); String builderClassName = className + "Builder"; System.out.println("생성자"); // Build the constructor MethodSpec constructor = MethodSpec.constructorBuilder() .addModifiers(Modifier.PUBLIC) .addStatement("this.object = new " + className + "()") .build(); System.out.println("메서드"); // Build the build method MethodSpec buildMethod = MethodSpec.methodBuilder("build") .addModifiers(Modifier.PUBLIC) .returns(ClassName.get(packageName, simpleClassName)) .addStatement("return object") .build(); System.out.println("클래스"); // Create the builder class TypeSpec.Builder builderClassBuilder = TypeSpec.classBuilder(builderClassName) .addModifiers(Modifier.PUBLIC) .addField(ClassName.get(packageName, simpleClassName), "object", Modifier.PRIVATE) .addMethod(constructor) .addMethod(buildMethod); // Add setter methods String finalPackageName = packageName; setterMap.forEach((methodName, argumentType) -> { System.out.println(methodName + " : " + argumentType); MethodSpec setterMethod = MethodSpec.methodBuilder(methodName) .addModifiers(Modifier.PUBLIC) .returns(ClassName.get(finalPackageName, builderClassName)) .addParameter(ClassName.get(argumentType), "value") .addStatement("object.$L(value)", methodName) .addStatement("return this") .build(); System.out.println(setterMethod.toString()); builderClassBuilder.addMethod(setterMethod); }); System.out.println("클래스 빌드 완료"); TypeSpec builderClass = builderClassBuilder.build(); System.out.println("자바 파일"); // Create the Java file JavaFile javaFile = JavaFile.builder(packageName, builderClass).build(); System.out.println("파일 생성"); // Write the Java file JavaFileObject builderFile = processingEnv.getFiler().createSourceFile((packageName.equals("") ? "" : (packageName + ".")) + builderClassName); System.out.println(builderClassName); try (Writer writer = builderFile.openWriter()) { javaFile.writeTo(writer); } } }
Java
복사
processor
package org.example; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface BuilderProperty {}
Java
복사
annotation