해당 @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