2

I am using java annotation processing API with JavaPoet to generate a file and maven to compile my project.

It works as expected, resulting file is generated under /target/generated-sources/annotations/sk/typek/generated/TestGeneratedClass.java.

However, any subsequent mvn compile fails with Caused by: javax.annotation.processing.FilerException: Attempt to recreate a file for type sk.typek.generated.TestGeneratedClass.

I know i can just call mvn clean before every recompiling (then it works again), but i dont want to do that. Other annotation processing libraries i used before didnt have this problem so they handled it somehow.

Is there any way to "force overwrite" if generated file already exists? Or is it possible to delete old generated file (if it exists) as a part of my annotation processing code?

I searched for solution but couldnt find anything useful.

My annotation processor looks like this:

package sk.typek.annotation;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;

@SupportedAnnotationTypes("sk.typek.annotation.TestAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class TestAnnotationProcessor extends AbstractProcessor {
    private Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.filer = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        if (annotations.isEmpty()) {
            return false;
        }
        System.out.println("Processing annotations: " + annotations);
        try {

            TypeSpec.Builder classBuilder = TypeSpec.classBuilder("TestGeneratedClass")
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL);

            JavaFile javaFile = JavaFile.builder("sk.typek.generated", classBuilder.build())
                    .build();
            System.out.println("Writing file TestAnnotation to package " + javaFile.packageName);
            // tried this doesnt work
            if (javaFile.toJavaFileObject().delete()) {
                System.out.println("Deleted previously generated file");
            }
            javaFile.writeTo(filer);
        } catch (IOException e) {
            throw new DiffBuilderAnnotationProcessorException(e);
        }
        return true;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Collections.singleton(TestAnnotation.class.getCanonicalName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}
hendrix
  • 3,364
  • 8
  • 31
  • 46

1 Answers1

1

Looking at your code, it seams pretty clear, why you got the error message. Every time a mvn compile is done, the processor creates a file - even the processor do not need to.

You need to ask the processor, if it is necessary to recreate the file. You can do that by asking the processor for a list of elements to create:

roundEnv.getElementsAnnotatedWith(TestAnnotation.class))

This will return a list of elements annotated with TestAnnotation that was changed/needs to build since the last compile. After a mvn clean the list will contain all elements.

Changing your code to:

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
    if (annotations.isEmpty()) {
        return false;
    }
    System.out.println("Processing annotations: " + annotations);
    for (Element element : roundEnv.getElementsAnnotatedWith(TestAnnotation.class)) {
        try {
            TypeSpec.Builder classBuilder = TypeSpec.classBuilder("TestGeneratedClass")
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL);

            JavaFile javaFile = JavaFile.builder("sk.typek.generated", classBuilder.build())
                    .build();
            System.out.println("Writing file TestAnnotation to package " + javaFile.packageName);
            // tried this doesnt work
            if (javaFile.toJavaFileObject().delete()) {
                System.out.println("Deleted previously generated file");
            }
            javaFile.writeTo(filer);
        } catch (IOException e) {
            throw new DiffBuilderAnnotationProcessorException(e);
        }
    }
    return true;
}

should avoid the message.

El Hoss
  • 3,767
  • 2
  • 18
  • 24