简体   繁体   中英

Java annotation processing edit file created by annotation processer with other annotation processor

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?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM