Home » Language IDEs » Java Development Tools (JDT) » APT generated classes aren't compiled
APT generated classes aren't compiled [message #248564] |
Wed, 10 October 2007 11:18  |
Eclipse User |
|
|
|
Hi,
I wrote an AnnotationProcessor that on process() gather information
about the annotated types and register a RoundCompleteListener that on
roundComplete(RoundCompleteEvent) generate some java files (there isn't a
1:1 correspondence between annotated types and generated files, each
generated has information about one or more annotated types). The
processor runs as expected and generates the java files without problem,
but the classes aren't automatically compiled after generation. The
generated source folder is in the build path and the java files don't
contain any errors. I can force the compilation by trivially editing the
generated file (e.g. add/remove whitespace and save), after that the
class appear in the bin folder and Eclipse recognizes it.
Another processor I wrote don't have this problem (both are defined in
the same jar), but it generate the files on process() as usual.
While debugging it I noticed that the RoundState for the event is this:
classFilesCreated() = false
sourceFilesCreated() = false
errorRaised() = false
finalRound() = true
Perhaps because it's after the finalRound() Eclipse don't see the
generated java files. I failed to find a cause for this problem or
something similar online or in the APT documentation (i.e. I don't know if
it's expected behavior to ignore classes not generated on process()). Any
thoughts?
Best regards,
Daniel Yokomizo.
|
|
|
Re: APT generated classes aren't compiled [message #248627 is a reply to message #248564] |
Wed, 10 October 2007 17:55   |
Eclipse User |
|
|
|
Originally posted by: wharley.bea.com
"Daniel Yokomizo" <dyokomiso@sao.politec.com.br> wrote in message
news:7e69961ca72ba39c3d6fe4453dc30399$1@www.eclipse.org...
> Hi,
>
> I wrote an AnnotationProcessor that on process() gather information
> about the annotated types and register a RoundCompleteListener that on
> roundComplete(RoundCompleteEvent) generate some java files (there isn't a
> 1:1 correspondence between annotated types and generated files, each
> generated has information about one or more annotated types). The
> processor runs as expected and generates the java files without problem,
> but the classes aren't automatically compiled after generation. [...]
> Perhaps because it's after the finalRound() Eclipse don't see the
> generated java files. I failed to find a cause for this problem or
> something similar online or in the APT documentation (i.e. I don't know if
> it's expected behavior to ignore classes not generated on process()). Any
> thoughts?
I'll have to try this on Sun's apt tool to see what it does. In general, I
don't know of any other examples of generating java files during a
RoundComplete listener. Round-complete processing is mainly useful for
generating text files, such as web.xml, that contain summary information
accumulated during processing, or for reporting global errors. In fact in
the javax.annotation.processing API, which supplanted Sun's proprietary
com.sun.mirror interface in Java 6, I think it's illegal to generate java
types during the final round; but like you I can't currently find that in
the documentation.
You should note also that the set of types your processor is asked to
process is *not* necessarily the full set of types in your project, unless
you're doing a full clean build or your processor is set to run in "batch
mode". In incremental builds, only some types will be processed. This can
be a hazard for processors that try to aggregate information in the way you
suggest. In general, aggregation is very hard to get to work, which is one
of the big problems with this interface.
The documentation on the Mirror API is inconsistent and confusing where it
exists at all. The javax.annotation.processing information is a bit more
verbose, but still seems to contain many inconsistencies, misleading
phrasings, and missing parts. For example, nowhere in either API does there
seem to be a simple, straightforward explanation of what the rounding
algorithm is or what "final round" means.
Does your processor work as expected with the command-line apt tool?
-Walter Harley
JDT APT team
|
|
| |
Re: APT generated classes aren't compiled [message #248646 is a reply to message #248631] |
Wed, 10 October 2007 21:01   |
Eclipse User |
|
|
|
Originally posted by: wharley.bea.com
"Walter Harley" <wharley@bea.com> wrote in message
news:fejo1l$rci$1@build.eclipse.org...
> "Walter Harley" <wharley@bea.com> wrote in message
> news:fejhp2$bfd$1@build.eclipse.org...
>> [...]
>> I'll have to try this on Sun's apt tool to see what it does.
>
> Sun's apt spits out the following message: "warning: Cannot create file
> 'd:\temp\gen\Foo.java' after a round has ended" and then it throws an
> IOException from the createSourceFile() method.
>
> I fear that the idea of generating a Java file outside of the process()
> method is probably not going to be very successful. We could probably
> make it work in the Eclipse implementation, but I don't think it is
> supported by Sun, and I am pretty sure (although I can't find it!) that
> I've read it is not permitted in the javax.annotation.processing API
> either.
There is one variant of this that is supported by apt and not by Eclipse.
That is if the file is opened with createSourceFile() in the process()
method, but not closed until the RoundCompleteListener. In apt this works,
and the generated file is compiled; in Eclipse the file is generated but not
compiled.
I've entered https://bugs.eclipse.org/bugs/show_bug.cgi?id=205998 to report
this; Daniel, feel free to cc yourself on that bug and/or add details on
your particular use case, if relevant.
However, this situation is awkward because the Processor object is created
anew on each round in apt, so to make this work you need to store the
PrintWriter in a static variable. If you do that, then in Eclipse, it lasts
for an entire editing session, unless you mark the processor to run in batch
mode. There are probably ways around that, but to be frank, given these
oddities and given that the issue does not exist in
javax.annotation.processing, I would say we probably will not devote any
resources to fixing this bug unless there is a compelling and specific use
case. If you have such a case, please add it to the bug report.
Thanks,
-Walter Harley
JDT APT team
|
|
|
Re: APT generated classes aren't compiled [message #248712 is a reply to message #248646] |
Thu, 11 October 2007 16:44   |
Eclipse User |
|
|
|
Walter Harley wrote:
> "Walter Harley" <wharley@bea.com> wrote in message
> news:fejo1l$rci$1@build.eclipse.org...
>> "Walter Harley" <wharley@bea.com> wrote in message
>> news:fejhp2$bfd$1@build.eclipse.org...
>>> [...]
>>> I'll have to try this on Sun's apt tool to see what it does.
>>
>> Sun's apt spits out the following message: "warning: Cannot create file
>> 'd:tempgenFoo.java' after a round has ended" and then it throws an
>> IOException from the createSourceFile() method.
I was still developing the tool so I didn't test it with command line apt.
I'll have to implement the workaround you found below.
> [...]
> There is one variant of this that is supported by apt and not by Eclipse.
> That is if the file is opened with createSourceFile() in the process()
> method, but not closed until the RoundCompleteListener. In apt this works,
> and the generated file is compiled; in Eclipse the file is generated but not
> compiled.
Thanks for discovering this.
> I've entered https://bugs.eclipse.org/bugs/show_bug.cgi?id=205998 to report
> this; Daniel, feel free to cc yourself on that bug and/or add details on
> your particular use case, if relevant.
> However, this situation is awkward because the Processor object is created
> anew on each round in apt, so to make this work you need to store the
> PrintWriter in a static variable. If you do that, then in Eclipse, it lasts
> for an entire editing session, unless you mark the processor to run in batch
> mode.
I'm using it as a instance variable of my AnnotationProcessorFactory,
initialized at construction. I understand that a single instance of each
AnnotationProcessorFactory will be created for every run of apt. This also
solve the problem of the processing set being smaller than the complete
set (i.e. I keep a map of processed types and the aggregate files
necessary to be generated, so I generate all every time). The only problem
I see is if eclipse discard my AnnotationProcessorFactory and runs it with
a smaller set, but I'll get compile/test errors in this case, but a full
rebuild is just a couple clicks anyway. Also I don't keep the generated
files on our repository, so our build process will run apt with the entire
set anyway. I'm sure our testing process will ensure that no generation
bugs occur (also there's lot of places that statically depend on the
generated files and if javac fails to detect that a class doesn't exist
I'll have a much bigger problem to worry about ;).
> There are probably ways around that, but to be frank, given these
> oddities and given that the issue does not exist in
> javax.annotation.processing, I would say we probably will not devote any
> resources to fixing this bug unless there is a compelling and specific use
> case. If you have such a case, please add it to the bug report.
A workaround I discovered yesterday for Eclipse is to create a dummy
source file on process() (i.e. I write a empty interface declaration) and
on roundCompleted() I overwrite the file with everything I need. It'll
probably work on apt if I use createTextFile instead (on roundCompleted),
I'll test it later.
> Thanks,
>
> -Walter Harley
> JDT APT team
Thanks for your fast and complete response.
Daniel Yokomizo.
|
|
|
Re: APT generated classes aren't compiled [message #248717 is a reply to message #248712] |
Thu, 11 October 2007 18:47  |
Eclipse User |
|
|
|
Originally posted by: wharley.bea.com
"Daniel Yokomizo" <dyokomiso@sao.politec.com.br> wrote in message
news:a216ecc4d90c939d10be97ece9637507$1@www.eclipse.org...
>
> I'm using it as a instance variable of my AnnotationProcessorFactory,
> initialized at construction. I understand that a single instance of each
> AnnotationProcessorFactory will be created for every run of apt.
"Every run of apt," within the Eclipse IDE, is not a well-defined concept
unless you are running the processor in batch mode (settable with the
Factory Path / Advanced prefs dialog). In batch mode, the processor runs
only in build, not in reconcile, and the classloader is dumped on every
build. This causes poor performance but means that statics and factory
fields behave a bit more like apt command line mode. Batch mode is only
available for processors in jars, not processors in plug-ins.
> A workaround I discovered yesterday for Eclipse is to create a dummy
> source file on process() (i.e. I write a empty interface declaration) and
> on roundCompleted() I overwrite the file with everything I need. It'll
> probably work on apt if I use createTextFile instead (on roundCompleted),
> I'll test it later.
You don't need any dummy contents; you can just open the file, and then
write its contents and close it in roundCompleted(). It's not going to be
compiled until after roundCompleted() is done.
That's true for build, anyway. For reconcile, i.e. while you're typing in
the editor, you might get odd results.
You should definitely *not* use createTextFile() to write a Java source
file. Eclipse will not compile such files, and I don't think apt will
either; in javax.annotation.processing (the Java 6 version of this) it is
explicitly stated that even if you create a file named .java with
createTextFile() it is not allowed to be compiled.
|
|
|
Goto Forum:
Current Time: Tue Jul 15 05:14:09 EDT 2025
Powered by FUDForum. Page generated in 0.11313 seconds
|