Bug 379347 - APT ignores custom output folder settings
Summary: APT ignores custom output folder settings
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: APT (show other bugs)
Version: 3.8   Edit
Hardware: PC Mac OS X - Carbon (unsup.)
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Generic inbox for the JDT-APT component CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-12 19:30 EDT by Gleb Frank CLA
Modified: 2022-07-21 16:36 EDT (History)
2 users (show)

See Also:


Attachments
A test project demonstrating the problem (6.85 KB, application/java-archive)
2012-05-12 19:31 EDT, Gleb Frank CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Gleb Frank CLA 2012-05-12 19:30:13 EDT
Build Identifier: Version: Indigo Service Release 2 Build id: 20120216-1857

These days it is possible to set a custom output folder for each source folder (There's a checkbox on the Source tab of the Build Path configuration pane to "Allow output folders for source folders."

If you use that setting and set up a custom output folder O for a given source folder S, Eclipse will place the compiled classes for Java files originating in S into O.

However, when an annotation processor tries to write out a file into StandardLocation.CLASS_OUTPUT, it does not end up in O, but rather in the default output folder for the project.

Where this is important is, for example, for Maven projects, where you have the main source folder and also a test source folder, and you want to keep the results of annotation processing of each separated.

Reproducible: Always

Steps to Reproduce:
I'm going to attach a test project that demonstrates the problem. There are 2 source folders (src and src2). The default output folder is bin. src2 has a custom output folder, bin2. An annotation processor creates an extra file for each class annotated with SimpleAnnotation, right next to the class file itself. 

Class Test1 is in src, its package is com.example.aptTest1, and so its class file ends up in bin/com/example/aptTest1/Test1.class, and the corresponding generated resource is at bin/com/example/aptTest1/Test1.txt.

Class Test2 is in src2, its package is com.example.aptTest2. Its class file is placed at bin2/com/example/aptTest2/Test2.class. But the corresponding generated resource goes to bin/com/example/aptTest2/Test2.txt.
Comment 1 Gleb Frank CLA 2012-05-12 19:31:14 EDT
Created attachment 215533 [details]
A test project demonstrating the problem
Comment 2 Walter Harley CLA 2012-05-13 21:58:07 EDT
There is no relationship between where an annotation is found and where an annotation processor generates code; annotations _trigger_ processing, but then the processor is free to do whatever it wants.

So I am not sure how the compiler is supposed to know which output folder you want the files generated into?  Can you clarify the precise behavior you are looking for?

For example, let's suppose that you have two source folders, S1 and S2.  S1/a/Test1.java and S2/b/Test2.java both contain annotation @Foo.  You have an annotation processor that processes @Foo, and its process() method simply generates a new class, g/Gen.java.  In the first round of compilation, the processor will be called once (because at least one file was annotated with @Foo).  Which folder should Gen.java be generated into?
Comment 3 Gleb Frank CLA 2012-05-13 22:12:26 EDT
I'm not talking about code generation, actually, but resource generation. Those files do not go into the generated sources directory (StandardLocation.SOURCE_OUTPUT), but into the *class* output directory (StandardLocation.CLASS_OUTPUT), i.e. the same place where compiled classes go.
Comment 4 Walter Harley CLA 2012-05-13 23:54:48 EDT
Sure, but it's the same issue, isn't it?  If you have more than one class output directory, and a processor writes a file to the CLASS_OUTPUT location, how should the compiler know which one it means?
Comment 5 Gleb Frank CLA 2012-05-14 00:36:52 EDT
Not quite, I believe. This issue seems like it should be easier (granted, I am not familiar with implementation details of Eclipse's Java compiler.)

Here's what I think the crucial difference is: in this case, we know that the compiler *knows* what the current output directory is, because that's where it is putting the class files!

In my example above, the compiler knows to put Test2.class under bin2 and not bin. But the annotation processor's ProcessingEnvironment creates a resource file for Test2.txt under bin.

So it would seem that somehow the information about the current output directory is not being communicated to APT, or something like that.
Comment 6 Walter Harley CLA 2012-05-14 01:44:10 EDT
I think the way it works is that the compiler associates input folders with output folders. So it knows, for instance, that if you are compiling a .java file in folder As, and you have specified output folder Ao to go with source folder As, then it will put the .class file in Ao.

That works because there is a 1:n mapping from source files to class files: a .java file generates one .class file for every contained class (including anonymous inner classes and so forth), but two .java files never contribute to the same .class file.

That logic does not apply to annotation processor output, though.  An annotation processor runs once per compilation round, and it takes the entire pre-existing typesystem (including all compiled source files and everything on the classpath) as input.  Annotation processors don't generate one output file per input file: they can, and often do, generate one output file for multiple input files.

So, there is no way to associate the output file with a particular input file; and therefore, no way to determine the output folder.

Unless I'm misunderstanding something?
Comment 7 Gleb Frank CLA 2012-05-14 02:32:13 EDT
Ah, I see, I somehow thought different source folders were done in different invocations of the compiler... If that were the case, there would be only one output directory in effect at any given time. 

Yes, that makes it more difficult, not sure how to attack it. The methods in Filer do take originating elements as parameters, so in theory these could be used to pick an output directory, but as you say, that would not help in cases of originating elements spanning multiple source directories.
Comment 8 Matt Kusnierz CLA 2013-09-24 07:53:42 EDT
This leads to a specific problem with the org.kohsuke.metainf-services annotation processor when used with maven and eclipse. The annotation processor generates the META-INF/services files that are read by the java.util.ServiceLoader. The problem is that because eclipse sees both /src/main/java and src/test/java as equivalent source folders, both normal and tests classes are processed by the annotation processor. Annotated service test classes therefore appear in the same META-INF/services folder as do the regular non-test classes. The problem comes then at runtime when eclipse uses the maven classpath which excludes the test classes. The ServiceLoader therefore sees entry in META-INF/services for the test classes, but fails to load them because they are not on the classpath. And so you get a ClassNotFoundException.
Comment 9 Eclipse Genie CLA 2020-07-14 10:22:22 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 10 Eclipse Genie CLA 2022-07-21 16:36:49 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.