注释处理器生成像lombok这样的类

问题描述 投票:0回答:1

嗨,我开始使用 gradle 在 Java 中学习注释处理,遵循多项目结构:

ROOT
|
|-sample  # contains main classes
|-annotation # annotations read by processor
|-processor # processor to generate code

我尝试创建一个注释,就像 lombok @Builder 一样,我可以在 build/ generated/sources/annotationProcessor/java 中生成一个类...但是如果我尝试在带注释的类中的同一个包中生成类,但构建任务失败说我尝试替换文件

样品:

plugins {
    id("java")
}

group = "br.com.dio"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation(project(":annotation"))
    compileOnly(project(":annotation"))
    implementation(project(":processor"))
    annotationProcessor(project(":processor"))
}

处理器:

plugins {
    id("java")
}

group = "br.com.dio"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

val autoServiceVersion = "1.1.1"

dependencies {
    compileOnly("com.google.auto.service:auto-service:$autoServiceVersion")
    annotationProcessor("com.google.auto.service:auto-service:$autoServiceVersion")
    implementation("com.squareup:javapoet:1.13.0")
}

注释:

plugins {
    id("java")
}

group = "br.com.dio"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
}

设置.gradle.kts

rootProject.name = "annotation-processor"
include("processor")
include("sample")
include("annotation")

按照我的代码操作:

public class BuilderProcessor extends AbstractProcessor {

    @Override
    public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
                Map<String, TypeMirror> fields =element.getEnclosedElements().stream()
                        .filter(e -> e.getKind() == FIELD)
                        .collect(Collectors.toMap(e -> e.getSimpleName().toString(), Element::asType));
                final var packageName = processingEnv.getElementUtils().getPackageOf(element).toString();
                final var className = element.getSimpleName().toString();
                final var fullNameClass = packageName + "." + className;
                final var typeSpec = new BuilderCreate().create(packageName, className, fields);
                var javaFile = JavaFile.builder(packageName, typeSpec)
                        .indent("    ")
                        .build();
                try(
                        var out = new PrintWriter(processingEnv.getFiler()
                                .createSourceFile(className)
                                .openWriter()
                        )
                ){
                    out.println(javaFile);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return true;
    }

}
java gradle annotations annotation-processing
1个回答
0
投票

为了解决这个问题,我完成了它使用注释处理器在另一个文件中创建一个构建器类,我想如何修改生成文件并创建一个内部构建器,如lombok,但在评论中Slaw帮助我理解这更复杂(这是我第一次使用注释处理器)遵循我的最终代码:

@SupportedAnnotationTypes("br.com.dio.annotation.Builder")
@SupportedSourceVersion(SourceVersion.RELEASE_21)
@AutoService(Processor.class)
public class BuilderProcessor extends AbstractProcessor {

    @Override
    public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            for (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {
                Map<String, TypeMirror> fields =element.getEnclosedElements().stream()
                        .filter(e -> e.getKind() == FIELD)
                        .collect(Collectors.toMap(e -> e.getSimpleName().toString(), Element::asType));
                final var packageName = processingEnv.getElementUtils().getPackageOf(element).toString();
                final var className = element.getSimpleName().toString();
                final var builderName = className + "Builder";


                final var typeSpec = new BuilderCreate().create(packageName, className, builderName,fields);
                var javaFile = JavaFile.builder(packageName, typeSpec)
                        .indent("    ")
                        .build();
                try(
                        var out = new PrintWriter(processingEnv.getFiler()
                                .createSourceFile(className + "Builder")
                                .openWriter()
                        )
                ){
                    out.write(javaFile.toString());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return true;
    }

}

public class BuilderCreate {

    public TypeSpec create(final String packageName, final String className,
                           final String builderName,final Map<String, TypeMirror> fields){
        var generatedBuilderClass = TypeSpec.classBuilder(builderName)
                .addModifiers(PUBLIC);

        fields.forEach((k, v) -> generatedBuilderClass.addField(TypeName.get(v), k, PRIVATE));
        fields.forEach((k, v) -> generatedBuilderClass.addMethod(buildBuilderSetter(
                        packageName,
                        builderName,
                        k,
                        TypeName.get(v))
                )
        );

        var buildMethod = MethodSpec.methodBuilder("build")
                .addModifiers(PUBLIC)
                .returns(ClassName.get(packageName, className))
                .addStatement("var target = new $N()", className);

        fields.keySet().forEach(f -> buildMethod.addStatement(
                "target.set$N($N)",
                f.substring(0,1).toUpperCase() + f.substring(1, f.length()),
                f)
        );
        buildMethod.addStatement("return target");

        return generatedBuilderClass.addMethod(buildMethod.build())
                .build();
    }

    private MethodSpec buildBuilderSetter(final String packageName, final String name, final String param, final TypeName type){
        return MethodSpec.methodBuilder(param)
                .addModifiers(PUBLIC)
                .returns(ClassName.get(packageName, name))
                .addParameter(type, param, FINAL)
                .addStatement("this.$N = $N", param, param)
                .addStatement("return this")
                .build();
    }

}

© www.soinside.com 2019 - 2024. All rights reserved.