3

I am trying to generate a config file for my sourcecode via compiletime annotation processing in Java 8.

As far as I understand for each Annotation listed in the getSupportedAnnotationTypes class, the processor gets called once.

 @Override public Set<String> getSupportedAnnotationTypes() { Set<String> set = new LinkedHashSet<>(); set.add(MCPlugin.class.getCanonicalName()); set.add(MCAPIVersion.class.getCanonicalName()); set.add(MCAuthor.class.getCanonicalName()); set.add(MCAPIVersion.class.getCanonicalName()); set.add(MCDepend.class.getCanonicalName()); set.add(MCLoad.class.getCanonicalName()); set.add(MCLoadBefore.class.getCanonicalName()); set.add(MCSoftDepend.class.getCanonicalName()); set.add(MCCommand.class.getCanonicalName()); return set; } 

Actually I don't want to process all those annotations with one annotation processer (Would this be the right way?) because it causes problems with the MCCommand annotation. So my plan was to create another annotation processer, which only processes the MCCommand annotations.

My problem is, that the output of both processers should go into the same output file. (Is that even possible?)

I have already tried to reopen the resource file like this (this is also how I open it in the first place):

FileObject file = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "config.yml"); 

which will only create an error or override the existing file.

TlDr: How can I make my annotation processer edit a file generated by another annotation processor?

2
  • Does Filer#getResource work? Commented Dec 5, 2019 at 22:43
  • 1
    No, sadly it just throws an FilerException saying "Atempt to reopen file..." Commented Dec 6, 2019 at 15:18

2 Answers 2

4

I know this is old, but it might help other people.

You can identify the file path and edit it as normal file (delete, truncate, append...).

In the process, the file will be created if it does not exist. But the content will not be deleted.

 public Path createIdentifyResource(String file) throws IOException { try { FileObject fileObject = processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, "", file); return new File(fileObject.toUri()).toPath(); } catch (IOException e) { FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", file); return new File(fileObject.toUri()).toPath(); } } 

The process is simple. First try to get the resource as if it exists. If it fails, it will attempt to create the resource. Finally, get the URI and convert it to Path.

Sign up to request clarification or add additional context in comments.

Comments

2

Okay, after hours of going through the sourcecode of the Filer and the FileObject I found a solution / workaround.

To be able to get access to the JavacFiler you need to have com.sun.tools as dependency.

Downcast the Filer to a JavacFiler to get access to more methods. The filer has a createResource(...) and a getResource(...) method, which seem to do the same but the difference is that createResource(...) opens a FileObject for writing only and the getResource(...) for reading only.

So to be able to edit a file from another Annotation Processor you have to do:

  1. open the file as read read only
  2. read the filecontent
  3. close the file
  4. reopen the file as write only
  5. write the old content to it
  6. add more data
FileObject jfo = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", "test.txt"); String msg = TUtils.JFOToString(jfo); // Reads FileObject as String jfo.delete(); jfo = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "test.txt"); TUtils.writeJFO(jfo, msg + "Hallo ich bin Processor 2"); // Writes String to FileObject filer.close(); 

This feels like a hack, but I seems to work.

3 Comments

This means that your annotation processor will not work in non-jre compilers, like Eclipse's JDT. Perhaps use reflection to test if the class is present before using it, and see what similar changes (if any) are needed to make JDT work in this case?
Thanks, I will note that for further development. Atm I am still struggeling with the two Processors accessing one resource.
In Java 8, the Filer interface does have both the get and create methods; why do you need a cast?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.