Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Language IDEs » Java Development Tools (JDT) » APT (Java 6) and JDT : What's wrong ? (Problem with Filer and the Annotation Processing facilities in Eclipse)
icon5.gif  APT (Java 6) and JDT : What's wrong ? [message #549168] Sun, 25 July 2010 17:27 Go to next message
Alexis Drogoul is currently offline Alexis DrogoulFriend
Messages: 5
Registered: July 2010
Junior Member
Hi,

[EDIT : Forgot to say that I'm working on Eclipse 3.6, fully up-to-date, on MacOS X 10.6.3 -- if that's of any help]


I've recently managed to get an Annotation Processor for Java 6 to work in Eclipse (not really easy, but this is another story). This processor's only function is to list (in a file called "classes.txt") the classes in my project that are annotated with specific annotations.

Here is its code :

 
@SupportedAnnotationTypes({ "my.own.Annotations.*" })
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class GamaProcessor extends AbstractProcessor {

	public GamaProcessor() {}

	@Override
	public boolean process(final Set<? extends TypeElement> elements, final RoundEnvironment env) {
		Messager messager = processingEnv.getMessager();
		Filer filer = processingEnv.getFiler();
		FileObject file = null;
		Writer writer = null;
		StandardLocation location = StandardLocation.SOURCE_OUTPUT;
		try {
			file = filer.createResource(location, "", "classes.txt", new Element[] {});
		} catch (FilerException e2) {
			try {
				file = filer.getResource(location, "", "classes.txt");
			} catch (IOException e) {
				return true;
			}
		} catch (IOException e) {
			return true;
		}
		try {
			writer = file.openWriter();
		} catch (IOException e1) {
			return true;
		}

		final PrintWriter out = new PrintWriter(writer, true);
		out.println("BEGIN CLASSES LIST");
		for ( TypeElement annotation : elements ) {
			String aName = annotation.getSimpleName().toString();
			Set<? extends Element> types = env.getElementsAnnotatedWith(annotation);
			for ( Element element : types ) {
				if ( element.getKind() == ElementKind.CLASS ) {
					String msg = aName + " annotates " + element.getSimpleName().toString();
					out.println(msg);
					messager.printMessage(Kind.ERROR, msg, element);
				}
			}

		}
		out.println("END CLASSES LIST");
		out.close();

		return true;
	}
}




Nothing too complicated, at first glance. I create a text file (or get the existing one if the file already exists), then process the elements annotated to write the same message both in the file and in the error reporter of Eclipse (just to get sure the right elements are processed : this operation will of course be trashed in the production processor).

What are the results ? Well... Surprising (to speak frankly, I've spent 2 days on this without any progress, and I just give up trying to understand what's happening so I hope someone will be able to help me).

1) The messages are correctly reported as errors in Eclipse. So the processor at least processes something, the annotations are correctly found, the compiler correctly invokes the processor, the messages are good old Strings, etc.

2) Problem is, none of these messages are written in the file. BUT (a) the file is created in the right directory (b) At the end of the build (and after a refresh to be sure) the lines "BEGIN CLASSES LIST" (before main loop) and "END CLASSES LIST" (after main loop) are both written in it ... which means that the processor can access it without problems, but visibly not from within the main loop...

What's happening here ? Why is a simple println(String) executed before and after the loop but not inside ? Am I missing something so simple I can't see it ? I've tried a lot of workarounds, but they all give the same results and I now find myself really lost and would appreciate any help.

Thanks in advance !

Cheers

Alexis

[Updated on: Sun, 25 July 2010 18:15]

Report message to a moderator

Re: APT (Java 6) and JDT : What's wrong ? [message #549234 is a reply to message #549168] Mon, 26 July 2010 08:38 Go to previous messageGo to next message
Satyam Kandula is currently offline Satyam KandulaFriend
Messages: 444
Registered: July 2009
Senior Member
The file is probably getting overwritten. You may either try to append the file or guard against empty elements.
Re: APT (Java 6) and JDT : What's wrong ? [message #549461 is a reply to message #549168] Mon, 26 July 2010 17:05 Go to previous messageGo to next message
Walter Harley is currently offline Walter HarleyFriend
Messages: 847
Registered: July 2009
Senior Member
"Alexis Drogoul" <alexis.drogoul@gmail.com> wrote in message
news:i2hs6s$v3c$1@build.eclipse.org...
> Hi,
>
> I've recently managed to get an Annotation Processor for Java 6 to work in
> Eclipse (not really easy, but this is another story). This processor's
> only function is to list (in a file called "classes.txt") the classes in
> my project that are annotated with specific annotations.
> Here is its code :
>
>
> @SupportedAnnotationTypes({ "my.own.Annotations.*" })
> @SupportedSourceVersion(SourceVersion.RELEASE_6)
> public class GamaProcessor extends AbstractProcessor {
>
> public GamaProcessor() {}
>
> @Override
> public boolean process(final Set<? extends TypeElement> elements, final
> RoundEnvironment env) {
> Messager messager = processingEnv.getMessager();
> Filer filer = processingEnv.getFiler();
> FileObject file = null;
> Writer writer = null;
> StandardLocation location = StandardLocation.SOURCE_OUTPUT;
> try {
> file = filer.createResource(location, "", "classes.txt", new Element[]
> {});
> } catch (FilerException e2) {
> try {
> file = filer.getResource(location, "", "classes.txt");
> } catch (IOException e) {
> return true;
> }
> } catch (IOException e) {
> return true;
> }
> try {
> writer = file.openWriter();
> } catch (IOException e1) {
> return true;
> }
>
> final PrintWriter out = new PrintWriter(writer, true);
> out.println("BEGIN CLASSES LIST");
> for ( TypeElement annotation : elements ) {
> String aName = annotation.getSimpleName().toString();
> Set<? extends Element> types = env.getElementsAnnotatedWith(annotation);
> for ( Element element : types ) {
> if ( element.getKind() == ElementKind.CLASS ) {
> String msg = aName + " annotates " + element.getSimpleName().toString();
> out.println(msg);
> messager.printMessage(Kind.ERROR, msg, element);
> }
> }
>
> }
> out.println("END CLASSES LIST");
> out.close();
>
> return true;
> }
> }
>
>
>
>
> Nothing too complicated, at first glance. I create a text file (or get the
> existing one if the file already exists), then process the elements
> annotated to write the same message both in the file and in the error
> reporter of Eclipse (just to get sure the right elements are processed :
> this operation will of course be trashed in the production processor).
> What are the results ? Well... Surprising (to speak frankly, I've spent 2
> days on this without any progress, and I just give up trying to understand
> what's happening so I hope someone will be able to help me).
>
> 1) The messages are correctly reported as errors in Eclipse. So the
> processor at least processes something, the annotations are correctly
> found, the compiler correctly invokes the processor, the messages are good
> old Strings, etc.
>
> 2) Problem is, none of these messages are written in the file. BUT (a) the
> file is created in the right directory (b) At the end of the build (and
> after a refresh to be sure) the lines "BEGIN CLASSES LIST" (before main
> loop) and "END CLASSES LIST" (after main loop) are both written in it ...
> which means that the processor can access it without problems, but visibly
> not from within the main loop...
> What's happening here ? Why is a simple println(String) executed before
> and after the loop but not inside ? Am I missing something so simple I
> can't see it ? I've tried a lot of workarounds, but they all give the same
> results and I now find myself really lost and would appreciate any help.
>
> Thanks in advance !


As Satyam pointed out, you're probably overwriting the file. Some things to
notice here:

1. When running a processor inside the IDE (as opposed to with javac at the
command line), there is no guarantee that you will get _all_ annotated
elements in a single call to process(). That means that the 'elements'
argument in the process() call may not contain every annotated element. In
general it will only contain the ones that needed to be recompiled during
that build - this may only be a single element.

2. The process() method will always be called at least twice, if there are
any annotated elements: after all the ordinary processing rounds there is a
"final" round which can be used to output resources like the one you're
trying to write. If you try to open the same file for writing on more than
one round, you should get a FilerException. (There's a bug right now that
prevents that in some cases, but that will shortly be fixed, and this is
according to the JSR269 spec.) So your code needs to pay attention to
whether it's the final round.

I think probably you want to accumulate information in a temporary variable
during processing, and then in the final round, open the file (if it
exists), read it and add its contents to a list, and then output the entire
list back to the file.

It's always helpful to put some breakpoints inside the process() call and
step through it to see what's actually going on.
Re: APT (Java 6) and JDT : What's wrong ? [message #549466 is a reply to message #549461] Mon, 26 July 2010 17:38 Go to previous messageGo to next message
Alexis Drogoul is currently offline Alexis DrogoulFriend
Messages: 5
Registered: July 2010
Junior Member
Hi,

Thanks for your explanations. In the meantime, I've managed to have something running, but I'll revise it according to your comments, especially the fact that process() might be called several times on the same object... I haven't been able to figure it out, despite reading a lot documents...

However, I have two more questions then :

1) Isn't the "batch" mode supposed to allow the processor to work only for full builds (i.e. where you could expect to get all the classes at once) ? I have tried to put my processors in batch mode, but they remained active even for incremental builds (writing only one class).

2) How do you know that this is the "final" round ? Is it a property of RoundEnvironment ?

Thanks !

Alexis

Re: APT (Java 6) and JDT : What's wrong ? [message #549522 is a reply to message #549466] Tue, 27 July 2010 05:48 Go to previous messageGo to next message
Walter Harley is currently offline Walter HarleyFriend
Messages: 847
Registered: July 2009
Senior Member
"Alexis Drogoul" <alexis.drogoul@gmail.com> wrote in message
news:i2kh6c$dru$1@build.eclipse.org...
> Hi,
>
> Thanks for your explanations. In the meantime, I've managed to have
> something running, but I'll revise it according to your comments,
> especially the fact that process() might be called several times on the
> same object... I haven't been able to figure it out, despite reading a lot
> documents...
>
> However, I have two more questions then :
> 1) Isn't the "batch" mode supposed to allow the processor to work only for
> full builds (i.e. where you could expect to get all the classes at once) ?
> I have tried to put my processors in batch mode, but they remained active
> even for incremental builds (writing only one class).

Batch mode only applies for Java 5 processors. Java 6 processors are
supposed to be better behaved :-)


>
> 2) How do you know that this is the "final" round ? Is it a property of
> RoundEnvironment ?

Yes; RoundEnvironment.processingOver(). It's very confusingly documented,
because it never outright says that it's true during the final round, and it
also seems to suggest that it's okay to generate a new type during this
round when I believe in fact that is not permitted (and if it is, it
shouldn't be, because it makes no sense). You can generate new resources,
but not new Java files.
Re: APT (Java 6) and JDT : What's wrong ? [message #549533 is a reply to message #549522] Tue, 27 July 2010 06:41 Go to previous messageGo to next message
Alexis Drogoul is currently offline Alexis DrogoulFriend
Messages: 5
Registered: July 2010
Junior Member
Thanks ! I think the documentation for the APT support in Eclipse should be a little bit better with regard to the limitations of Java 6 processors. Maybe I'll introduce some enhancement request Smile

Regarding the fact that there seems to be no way to know if we are incrementally or fully building a project, I suppose it means that I have to allow for an incremental generation of my various resources (i.e. loading them in the first round, filling my intermediate structures with their content, than, in the final round, writing them again, in order to avoid wiping out the result of previous builds)... A little bit longer to write, but at least I'm sure I'll be behaving correctly Smile

Thanks for all your answers !

Cheers

Alexis
Re: APT (Java 6) and JDT : What's wrong ? [message #549969 is a reply to message #549533] Wed, 28 July 2010 15:21 Go to previous messageGo to next message
Walter Harley is currently offline Walter HarleyFriend
Messages: 847
Registered: July 2009
Senior Member
"Alexis Drogoul" <alexis.drogoul@gmail.com> wrote in message
news:i2lv1s$d4u$1@build.eclipse.org...
> Thanks ! I think the documentation for the APT support in Eclipse should
> be a little bit better with regard to the limitations of Java 6
> processors. Maybe I'll introduce some enhancement request :)

Or, you could contribute some fixes... the problem is not that we don't
know what needs to be done, it's that there are very few resources.

As for the Java 6 environment not supporting batch mode, though, that is by
design. Batch mode is a hack that was implemented to deal with specific
Java 5 processors that made assumptions that were only valid at the command
line; for example, keeping a count of processing rounds in a static variable
and not resetting it at the beginning of a new build. The Java 6 processing
API, and its javadoc, are designed somewhat better with regard to IDE
support, so this hack did not seem necessary.


>
> Regarding the fact that there seems to be no way to know if we are
> incrementally or fully building a project, I suppose it means that I have
> to allow for an incremental generation of my various resources (i.e.
> loading them in the first round, filling my intermediate structures with
> their content, than, in the final round, writing them again, in order to
> avoid wiping out the result of previous builds)... A little bit longer to
> write, but at least I'm sure I'll be behaving correctly :)

Yes, that's exactly right.

An alternative would be to put your processor in a subsequent build step,
for example, by calling it (from javac) in an Ant builder associated with
your project.

Thanks!
Re: APT (Java 6) and JDT : What's wrong ? [message #549978 is a reply to message #549969] Wed, 28 July 2010 15:40 Go to previous messageGo to next message
Alexis Drogoul is currently offline Alexis DrogoulFriend
Messages: 5
Registered: July 2010
Junior Member
Well... I've managed to have a nice incremental processor that does everything I need, and I thank you for the clarity of your comments, which helped me a lot !

However, I think I have uncovered a bug in one of the methods available on Element for getting the annotations. More specifically, it is one of the most exotic methods : <A extends Annotation> A getAnnotation(Class<A> annotationType);

(I know it's much safer to iterate through the TypeMirrors, etc. but this method is really convenient !).

Its documentation clearly states that "The annotation returned may be either inherited or directly present on this element.". However, I've discovered, after some tests, that only directly present annotations seem to be returned : inherited annotations are not discovered. Should I file a bug or something ?

Cheers

Alexis

Re: APT (Java 6) and JDT : What's wrong ? [message #550027 is a reply to message #549978] Wed, 28 July 2010 19:31 Go to previous message
Olivier Thomann is currently offline Olivier ThomannFriend
Messages: 518
Registered: July 2009
Senior Member
Please open a bug report against JDT/APT and provide steps to reproduce.
Thanks,

Olivier
Previous Topic:Java editor fails opening java file.
Next Topic:Ignoring Eclipse build/builders when modifying project structure/classpath
Goto Forum:
  


Current Time: Tue Sep 24 23:45:56 GMT 2024

Powered by FUDForum. Page generated in 0.04629 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top