Bug 79112 - [1.5] [model] accessing annotation on Java elements
Summary: [1.5] [model] accessing annotation on Java elements
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.3   Edit
Hardware: All All
: P2 enhancement with 13 votes (vote)
Target Milestone: 3.4 M3   Edit
Assignee: Jerome Lanneluc CLA
QA Contact:
URL:
Whiteboard:
Keywords: api
: 82554 106108 138230 149074 (view as bug list)
Depends on:
Blocks: 77121 209996
  Show dependency tree
 
Reported: 2004-11-19 15:58 EST by Jim des Rivieres CLA
Modified: 2007-12-05 12:03 EST (History)
37 users (show)

See Also:


Attachments
Proposed API version 1 (6.11 KB, text/plain)
2007-10-03 09:54 EDT, Jerome Lanneluc CLA
no flags Details
Proposed API version 2 (10.57 KB, text/plain)
2007-10-08 11:59 EDT, Jerome Lanneluc CLA
no flags Details
Proposed API version 3 (10.80 KB, text/plain)
2007-10-12 10:33 EDT, Jerome Lanneluc CLA
no flags Details
Proposed API version 4 (12.62 KB, text/plain)
2007-10-15 11:57 EDT, Jerome Lanneluc CLA
no flags Details
Proposed API version 5 (12.69 KB, text/plain)
2007-10-18 08:01 EDT, Jerome Lanneluc CLA
markus.kell.r: review+
Details
Proposed API version 6 (13.14 KB, text/plain)
2007-10-22 13:11 EDT, Jerome Lanneluc CLA
no flags Details
Proposed API version 7 (16.56 KB, text/plain)
2007-10-23 11:19 EDT, Jerome Lanneluc CLA
no flags Details
Proposed API version 8 (16.29 KB, text/plain)
2007-10-23 17:12 EDT, Jerome Lanneluc CLA
no flags Details
Implementation corresponding to proposed API version 8 (182.34 KB, patch)
2007-10-24 09:44 EDT, Jerome Lanneluc CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jim des Rivieres CLA 2004-11-19 15:58:48 EST
In J2SE5, package, class, field, and method declaration can all carry 
annotations.

Tools that work with Java code will need to be able to find out how a Java 
element has been annotated. They have no way to do this now.

The support that is there now in DOM/AST is no sufficient:
(1) Both Java compilation units and class files can carry annotations (DOM/AST 
only addresses annotations on source code).
(2) The annotations that client tools would be looking for would be best 
described as "resolved annotations" that would have defaulted values. 

This will require new API. Proposal: Add IJavaElemement.resolveAnnotations() 
to return a list of resolved annotations. The data structure used to represent 
the resolved annotations is the interesting part. The value of an annotation 
type member can be a primitive type, String, Class, annotation, enumeration, 
or 1-dimensional arrays thereof. The data structure must be capable of 
describing all of these. The classes that appear in the class literals, 
enumeration types, and annotation types, could be local classes, meaning that 
there is no way to refer to these things using any sort of qualified name. The 
most general way to represent these classes is to use an DOM/AST ITypeBinding:

public interface IResolvedAnnotation {
  ITypeBinding getAnnotationType();
  /** key is annotation member name
   * value is one of boxed primitive (Integer, Boolean, Character, etc.)
   * String, ITypeBinding (Class literals), IResolvedAnnotation (nested 
annotations), IVariable (enum constants)
   */
  public Map<String, Object> getValues();
}
Comment 1 Philipe Mulet CLA 2004-11-30 10:38:44 EST
Resolution should likely be optional (bridge to DOM AST when request ?).
In source model, bogus annotations are allowed (vs. resolved ones).
Also the source annotations should be containing sufficient information to
figure out what was explicitly supplied, vs. what is avaiable as a default.

Source annotations should thus not be resolved for real, but still provide
sufficient source information.
Comment 2 Jerome Lanneluc CLA 2005-01-11 09:31:38 EST
*** Bug 82554 has been marked as a duplicate of this bug. ***
Comment 3 Marshall Culpepper CLA 2005-03-29 11:56:35 EST
What is the status of this request? Are there workarounds that we can use in the
meantime to access the Annotation source model in the mean time?

Thanks.
Comment 4 Philipe Mulet CLA 2005-04-07 08:01:32 EDT
Deferring post 3.1
Comment 5 Mik Kersten CLA 2005-08-22 18:29:18 EDT
Is this getting planned for 3.2?  The proposal sounds great.
Comment 6 Markus Keller CLA 2006-06-08 12:13:01 EDT
The absence of the requested support for annotations in the java model drives clients into parsing the source themselves, see e.g. JavaLaunchableTester.
Comment 7 Frederic Fusier CLA 2006-09-08 12:15:48 EDT
Reopened as discussed at JDT/Summit
Comment 8 Christopher Daly CLA 2006-10-19 18:07:08 EDT
Can anyone on JDT team summarize what was discussed at JDT/Summit?

Which 3.3 milestone is this functionality targeted for?
Comment 9 Jerome Lanneluc CLA 2006-10-20 04:59:56 EDT
According to http://www.eclipse.org/jdt/ui/r3_3/JDT-Summit.html, we just said we were going to look at it. 
According to http://www.eclipse.org/jdt/core/r3.3/index.php, this item has no target milestone yet.
Comment 10 Jerome Lanneluc CLA 2007-03-19 12:56:41 EDT
Sorry we ran out of time for this one. This will have to be deferred.
Comment 11 Frederic Fusier CLA 2007-03-19 13:27:39 EDT
*** Bug 138230 has been marked as a duplicate of this bug. ***
Comment 12 David Saff CLA 2007-04-24 11:55:30 EDT
P5 looks like a long-term burying of the idea.  This seems a pretty reasonable core functionality for a Java IDE, unless Java language features after 1.4 are to be always afterthoughts, or there's another way to accomplish the same thing without parsing the text directly.
Comment 13 Philipe Mulet CLA 2007-04-24 12:47:58 EDT
Using the DOM AST, you can access all annotations, and find the bindings they resolve to. Supporting them in the JavaModel is different, since it wouldn't resolve anything (as other APIs there) but rather simply surface raw source informations. Would this be matching expectation as such ?

Comment 14 Christian Dupuis CLA 2007-04-25 07:01:15 EDT
(In reply to comment #13)
> Using the DOM AST, you can access all annotations, and find the bindings they
> resolve to. Supporting them in the JavaModel is different, since it wouldn't
> resolve anything (as other APIs there) but rather simply surface raw source
> informations. Would this be matching expectation as such ?

Could you provide a very small example or code snippet on how to use DOM AST to get the annotations? That would be really helpful. Thanks

Comment 15 Martin Aeschlimann CLA 2007-04-25 07:12:54 EDT
Building an AST for everything is too expensive. The unresolved information provided by the Java Model still has its value.
I also think this API is a 'must have', for consistency and completeness. I suggest to target it for 3.4.
Comment 16 Philipe Mulet CLA 2007-04-25 08:29:18 EDT
The DOM AST and JavaModel have different aims, the DOM AST is fine-grain information, expensive, lifecycle managed by client but very accurate. The JavaModel is more a general purpose lightweight story, with raw data, and uses LRU caches underneath to avoid using too much memory.

In that sense, having annotations on elements could make sense, but if they occur they would NOT denote resolved information for the same consistency reason invoked  here. This is the reason of my previous comment. If requestors are hoping for a model API to retrieve resolved annotations, then they are looking at the wrong place, and should rather use the DOM AST.

I don't disagree about having model source annotations in general... mostly name based API. Also unclear how much we would surface from the member pair values... 
Comment 17 Philipe Mulet CLA 2007-04-25 08:32:46 EDT
Martin - can you elaborate on "The unresolved information
provided by the Java Model still has its value." ?

What usecase do you have in mind?
Comment 18 Martin Aeschlimann CLA 2007-04-25 08:49:20 EDT
Two scenarios:
- Showing annotations in hovers
- In the JUnit 4 plugin, we show the 'Run As Junit test' shortcut only if the selection contains a test.
A test has annotation '@Test'. Right now, we always build an AST. With Java model support, we could avoid many of these ASTs when we see that there is no annotation called 'Test' on the IMethod.
Comment 19 Tom Mutdosch CLA 2007-06-01 10:56:54 EDT
I agree that better annotation support in JDT would be nice.  

Somewhat related to this request is another bug I have opened:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=190394

There's no real good way to listen for changes to annotations via the IJavaElementListener.  I think that probably goes hand-in-hand with better general annotation support on the Java model.
Comment 20 Alex Blewitt CLA 2007-07-03 14:50:39 EDT
Shouldn't the 'version' of this bug be updated to 3.3?
Comment 21 Jerome Lanneluc CLA 2007-07-04 04:37:48 EDT
(In reply to comment #20)
> Shouldn't the 'version' of this bug be updated to 3.3?
Sure. 

Comment 22 Philipe Mulet CLA 2007-07-04 06:10:55 EDT
re: comment 19.
Definitely, if annotations get reified, change notifications will be notified somehow. Note that the exact form of the notification will depend upon the way annotations are represented (could be children, flags etc...).
This isn't truly defined so far.

Thoughts are welcome.
Comment 23 Bruno Braga CLA 2007-09-07 14:58:35 EDT
Opened: 2004-11-19 15:58 -0400..., what it leaves me worried is that already passed 3 years since report... (21 votes)... also is needing very this feature :P
Comment 24 Philipe Mulet CLA 2007-09-10 06:01:14 EDT
Bruno - a patch is very welcome ! <g>
Comment 25 Bruno Braga CLA 2007-09-10 15:38:01 EDT
I always make patchs. You can look at in the Hibernate, Spring and other projects :)
But I found this problem now and at this moment I cannot act in it because I am solving a problem of another project Open Source. But we have 21 votes and some companies helping in the Eclipse. With certainty somebody goes to help... the Eclipse is an excellent project because of this :)
Comment 26 Cédric Chabanois CLA 2007-09-27 06:08:16 EDT
It is possible to get annotations :
(1) from Java compilation units (ICompilationUnit) using DOM/AST
(2) from class files (IClassFile) using org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader (but this is an internal class)

This is not easy and this is expansive.

So, I think this feature is really needed.
Comment 27 Cédric Chabanois CLA 2007-10-02 08:52:28 EDT
There is another way to get annotations :
One can use org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment and implement org.eclipse.jdt.internal.compiler.impl.ITypeRequestor.
This way, it works both for sources and class files. 
But these classes are internal and you will get classes from org.eclipse.jdt.internal.compiler.lookup (the old type binding).
And you cannot convert from old type binding (classes from org.eclipse.jdt.internal.compiler.lookup) to new type binding (classes from org.eclipse.jdt.core.dom) because org.eclipse.jdt.core.dom.DefaultBindingResolver is not public.
Comment 28 Jerome Lanneluc CLA 2007-10-03 09:54:32 EDT
Created attachment 79633 [details]
Proposed API version 1

Following comment 16, please find attached a first cut of the new API proposal. 

Before anyone asks why IAnnotationReference and not IAnnotation, it is because IAnnotation already exists in org.eclipse.jdt.core.util to represent an annotation  in a class file. So we wanted to avoid a name clash.

Also what do people expect the member's value of an annotation to be. In the proposal, it is the source if the annotation is from a source file, it is unspecified if it is from a class file. Or maybe people don't need this value ?

This is proposal is there to start the discussion. Please add your comments to this bug.
Comment 29 Jerome Lanneluc CLA 2007-10-08 11:59:09 EDT
Created attachment 79905 [details]
Proposed API version 2

After getting feedback privately, this new API proposal changes the following:
1. IAnnotationReference implements ISourceReference
2. the source positions of the reference can be retrieved using IAnnotationReference#getNameRange()
3. IAnnotationReference#getElementName() specifies what to expect
4. IAnnotationReference#getMembers() and getValues() have been replaced by getMemberValuePairs() that returns an array of IMemberValuePairs

Feedback is still welcome (positive or negative).
Comment 30 Martin Aeschlimann CLA 2007-10-09 04:03:56 EDT
The last API suggestion looks very good to me.
Comment 31 Carsten Pfeiffer CLA 2007-10-09 04:39:22 EDT
(In reply to comment #29)
> Created an attachment (id=79905) [details]
> Proposed API version 2

Thanks Jerome, this looks quite good to me. Two comments from me:

1) what do you think about write-access? E.g. 
    createAnnotation(String contents, AnnotationReference sibling, boolean
force, IProgressMonitor monitor) throws JavaModelException
and possibly 
    IAnnotationReference#createMemberValuePair(String contents,
IMemberValuePair sibling, boolean force, IProgressMonitor monitor) throws
JavaModelException

2) would it make sense to combine the methods getAnnotation() and
getAnnotations() (and possibly the above createAnnotation()) in an interface
IAnnotatable instead of "duplicating" them in IField, IType and IMethod?
Comment 32 Markus Keller CLA 2007-10-09 14:20:34 EDT
Yep, looks mostly fine.

I would prefer IAnnotation for the new IJavaElement, but if you really think we need another name, then I would just call the type IAnnotationReference but still use the single word "annotation" when describing an annotation in prose (like JLS3 9.7).

Do we need IMemberValuePair#isArrayValue()? I don't think there are many use cases where clients will not call IMemberValuePair#getValue() if the value is not an array, so this won't help much performance-wise.

What does IMemberValuePair#getValue() do if only some elements of an array-valued annotation could not be classified? I guess this would result in getValueKind() == K_UNKNOWN and getValue() being an array containing null elements. If so, callers should be warned about these potential null elements.

Is IMemberValuePair#getValue() a handle-only method, or should it throw a JME?

(In reply to comment #31)
> 2) would it make sense to combine the methods getAnnotation() and
> getAnnotations() (and possibly the above createAnnotation()) in an interface
> IAnnotatable instead of "duplicating" them in IField, IType and IMethod?

I agree. Moreover, annotations can also appear on IPackageDeclarations and ILocalVariables (including parameters), so I would also expect those to be IAnnotatable.

Javadocs for new methods are missing "This is a handle-only method."

There are also Javadocs in other IJavaElements that need to be updated, e.g. ISourceReference enumerates its sub-interfaces.

IMemberValuePair is currently not an IJavaElement, which prevents IMemberValuePairBinding#getJavaElement() from offering this link (I'm unsure whether that's important).

IAnnotationBinding#getJavaElement() should now return an IAnnotationReference.

Typos in IAnnotationReference's Javadoc: refernces, Retuns.
Comment 33 Brian Vosburgh CLA 2007-10-09 14:36:53 EDT
A few comments:

1. I second Carsten's idea (comment 31) of a common interface. (I would also like a common, slightly related, interface for all the DOM implementers of #modifiers() : List<IExtendedModifier> - e.g. BodyDeclaration, SingleVariableDeclaration. But that's another story....) This will simplify any code that reads (and possibly manipulates) annotations. We have lots of this type of code in the Dali project. Feel free to steal it.

2. But I'm not so enamored of Carsten's API (comment 31) for writing annotations, though. :-) The 'String contents' parameter in both methods feels a bit nebulous.... We would also need API for removing annotations and member value pairs. BUT, I agree that it would be very nice to be able to write to annotations. Of course the opens the Can of Worms of how you deal with conversions among marker, single-member, and normal annotations; and the back and forth between a single-and multi-element arrays....

3. IAnnotationReference needs a method like IMember#getOccurrenceCount() : int to indicate "the position relative to the order this [annotation reference] is defined in the source", for when the same annotation occurs, mistakenly, more than once.

4. How will you handle a single element array member whose curly braces are implied; e.g.
definition:
    public @interface Target {
        ElementType[] value();
    }
usages:
    @Target({METHOD, FIELD})
    @Target(METHOD)
Will IMemberValuePair#getValue() (for the "value" member value pair) return an array of names for both cases? Will #isArrayValue() return true in both cases? Or will the client need to watch for the cases where the array is implied? Obviously, I prefer a simpler client. : -)

5. I'm not sure Markus's comment about problematic arrays (comment 32) is relevant yet. :-) The parser has too many problems with annotations right now. See bug 130778.

app. I wish the feedback you received and acted upon in comment 29 had been captured here. :-( We have been dealing with annotations in Dali for quite a while now, and it would be nice to see other's experiences discussed here. It gets to feeling pretty lonely sometimes. :-)
Comment 34 Carsten Pfeiffer CLA 2007-10-10 12:35:12 EDT
(In reply to comment #33)
> 1. I second Carsten's idea (comment 31) of a common interface. (I would also
> 2. But I'm not so enamored of Carsten's API (comment 31) for writing
> annotations, though. :-) The 'String contents' parameter in both methods feels
> a bit nebulous.... We would also need API for removing annotations and member value pairs.

FWIW, I'm not too fond of the "String contents" either; I only used the existing createType(), createField, createInitializer, etc. methods as a reference.
Comment 35 Markus Keller CLA 2007-10-10 13:14:43 EDT
Re write access:
The create*(..) methods in existing IJavaElements are remnants of the days before ASTRewrite. They are just kept for compatibility. I don't think we need such a method on I(Resolved)Annotation, given that there are better ways now.
Comment 36 Jerome Lanneluc CLA 2007-10-11 04:58:47 EDT
Thanks to all who gave feedback. I'll try to come up with a new proposal that integrates your comments by the end of the week.
Comment 37 Jerome Lanneluc CLA 2007-10-12 10:33:01 EDT
Created attachment 80230 [details]
Proposed API version 3

As promised, here is the new API proposal after your feedback. Also I tried to answer each point you made below:

====================================================================
(In reply to comment #31)
> 1) what do you think about write-access?
You are right that this would be more consistent with the current API. However
as Markus pointed out, the recommended way to make changes to a compilation unit it to use the DOM/AST rewriting support. Let me think a little bit more about it. 
 
> 2) would it make sense to combine the methods getAnnotation() and
> getAnnotations() (and possibly the above createAnnotation()) in an interface
> IAnnotatable instead of "duplicating" them in IField, IType and IMethod?
That makes total sense. The new API proposal has now an IAnnotatable interface.

====================================================================
(In reply to comment #32)
> I would prefer IAnnotation for the new IJavaElement, [...]
From the feedback I got privately, others agree with you. So I renamed IAnnotationReference to IAnnotation. 

> Do we need IMemberValuePair#isArrayValue()? 
Agreed. This is now removed and the Javadoc has been updated accordingly.

> What does IMemberValuePair#getValue() do if only some elements of an
> array-valued annotation could not be classified? I guess this would result in
> getValueKind() == K_UNKNOWN and getValue() being an array containing null
> elements. If so, callers should be warned about these potential null elements.
Hopefully the Javadoc is clearer on this point now.
 
> Is IMemberValuePair#getValue() a handle-only method, or should it throw a JME?
Since IMemberValuePair is not a Java element handle, I don't think it makes sense to specify that.

> I agree. Moreover, annotations can also appear on IPackageDeclarations and
> ILocalVariables (including parameters), so I would also expect those to be
> IAnnotatable.
Thanks, I missed those. This is now fixed.

> Javadocs for new methods are missing "This is a handle-only method."
I believe the one that apply to handles are now correct.
 
> There are also Javadocs in other IJavaElements that need to be updated, e.g.
> ISourceReference enumerates its sub-interfaces.
Thanks. This is now fixed.

> IMemberValuePair is currently not an IJavaElement, which prevents
> IMemberValuePairBinding#getJavaElement() from offering this link (I'm unsure
> whether that's important).
I'm not sure either. Let me think about it.

> IAnnotationBinding#getJavaElement() should now return an IAnnotationReference.
Right.

> Typos in IAnnotationReference's Javadoc: refernces, Retuns.
Thanks. This is now fixed.

====================================================================
(In reply to comment #33)
> 1. [...] (I would also
> like a common, slightly related, interface for all the DOM implementers of
> #modifiers() : List<IExtendedModifier> [...]
Could you please enter a separate enhancement request for that ?

> 2. But I'm not so enamored of Carsten's API (comment 31) for writing
> annotations, though. :-) [...]
Please see my answer to Carsten.
 
> 3. IAnnotationReference needs a method like IMember#getOccurrenceCount()
Thanks, I missed this one. This is now fixed.

> 4. How will you handle a single element array member whose curly braces are
> implied; e.g.
> definition:
>     public @interface Target {
>         ElementType[] value();
>     }
> usages:
>     @Target({METHOD, FIELD})
>     @Target(METHOD)
Since the Java model is based on source only, no resolution is done. Thus
it cannot know that the curly braces are implied. So in the first case, the value will be an Object[], and in the second case, it will be a String.

> 5. I'm not sure Markus's comment about problematic arrays (comment 32) is
> relevant yet. :-) The parser has too many problems with annotations right now.
> See bug 130778.
We plan to improve the parser recovery in this area.
Comment 38 Markus Keller CLA 2007-10-12 14:53:16 EDT
(In reply to comment #37)
> Created an attachment (id=80230) [details] Proposed API version 3

1.
> > IAnnotationBinding#getJavaElement() should now return an IAnnotationReference.
> Right.
This would need to be corrected in Javadoc of IBinding.getJavaElement(), i.e. "For annotations, this methods returns the Java element of the annotation type." can be removed.

2.
IMemberValuePair: "To get the exact instance if this object, use its {@link #getValueKind() value kind}"
=> better:        "To get the *type* *of* this object [..]"

3.
IMemberValuePair#getValue() and #getValueKind(): I think we need to look at a few examples to get the array-valued cases right, e.g.:
    @Ann({1 + 2.3, 4.5})
    @Ann2({"string", "un" + "known"})
    @Broken({Color.UGLY, "yawn", 1+2})
	
#getValue(): "It is <code>null</code> if the value kind is {@link #K_UNKNOWN}". => This is strange, since it would not allow arrays with unknown elements.
	
#getValueKind(): I would expect either of these behaviors:

(a) If all array elements are of the same kind, #getValueKind() returns the determined kind. Otherwise, #getValueKind() returns K_UNKNOWN.

(b) If the value is an array, #getValueKind() returns a new constant K_ARRAY. The element kinds are not available from #getValueKind() any more (but clients can use #getValue() and inspect the array elements, like in the K_UNKNOWN case in (a)).

(c) Like (a), but the result of #getValueKind() is |-ed with K_ARRAY_MASK, such that clients can switch on
- fully resolved arrays: "case K_STRING | K_ARRAY_MASK:", and on
- the two problem cases: "case K_UNKNOWN:", "case K_UNKNOWN | K_ARRAY_MASK:".

Is there an implementation reason why #getValue() returns a String for K_QUALIFIED_NAME values but null for K_UNKNOWN? Wouldn't it be better to return the String for K_UNKNOWN as well for consistency? Otherwise, clients who still want to do something with the value would have to parse the whole annotation again.

4.
IMemberValuePair#K_CLASS: please use x.y.MyType.MyNestedType.class in the example to make clear that '.' is the type separator for all types (including nested binary types).
Comment 39 Jerome Lanneluc CLA 2007-10-15 11:57:23 EDT
Created attachment 80364 [details]
Proposed API version 4

(In reply to comment #38)
> > > IAnnotationBinding#getJavaElement() should now return an IAnnotationReference.
> > Right.
> This would need to be corrected in Javadoc of IBinding.getJavaElement(), i.e.
> "For annotations, this methods returns the Java element of the annotation
> type." can be removed.
IBinding#getJavaElement now appears in the proposed API.

> 2.
> IMemberValuePair: "To get the exact instance if this object, use its {@link
> #getValueKind() value kind}"
> => better:        "To get the *type* *of* this object [..]"
Thanks. This is now fixed.

> 3.
> IMemberValuePair#getValue() and #getValueKind(): I think we need to look at a
> few examples to get the array-valued cases right, [...]
Hopefully, this is now clarified. Especially see IMemberValuePair#K_UNKNOWN
where I tried to detail all the cases.

> #getValueKind(): I would expect either of these behaviors:
> 
> (a) If all array elements are of the same kind, #getValueKind() returns the
> determined kind. Otherwise, #getValueKind() returns K_UNKNOWN.
I chose this suggestion as I find it simpler than the other two.

> Is there an implementation reason why #getValue() returns a String for
> K_QUALIFIED_NAME values but null for K_UNKNOWN? Wouldn't it be better to 
> return the String for K_UNKNOWN as well for consistency? Otherwise, clients
> who still want to do something with the value would have to parse the whole
> annotation again.
The main reason is that I wanted to be consistent in the source case (value coming from a compilation unit, and the binary case (value coming from a .class file). In the binary case, we can only return null (or array of nulls). Another reason is to optimize space taken by the Java model cache. Also if a client needs to parse the source, IAnnotation#getSource() can be used.

> 4.
> IMemberValuePair#K_CLASS: please use x.y.MyType.MyNestedType.class in the
> example to make clear that '.' is the type separator for all types (including
> nested binary types).
This is now in the proposed API
Comment 40 Markus Keller CLA 2007-10-15 13:34:16 EDT
/** [..]
 * If the value kind is unknown, the returned value is always either <code>null</code>, or an 
 * array containing only <code>null</code>s.
 */
int K_UNKNOWN = 13;

/** [..]
 * If the value kind is {@link #K_UNKNOWN} and the value is an array, then the 
 * value is an array containing <code>null</code>s. [..]
 */
Object getValue();

That would mean that in the case below, IMemberValuePair#getValue() would return an Object[] with *only* null values? (How many?)

@SuppressWarnings({"nls", "deprecat" + Try.ION})
public class Try {
	public static final String ION= "ion";
}

I would remove the "only" from #K_UNKNOWN and change #getValue() to "is an array containing <code>null</code> for unknown elements".

Otherwise, the only value of the array would be to tell that there was an array (and maybe how many elements it contained). I don't think clients could do much with just this information, so if the API won't return the resolved array elements, you could as well say that #getValue() is null as soon as at least one element of the array is unknown.


> > Is there an implementation reason why #getValue() returns a String for
> > K_QUALIFIED_NAME values but null for K_UNKNOWN?
> The main reason is that I wanted to be consistent in the source case [..]
> and the binary case [..].

I don't think the values from a class file can be unknown, since they must have been constant expressions at compile time and the class file format looks like they are not computable. But omitting them for efficiency reasons is OK with me.
Comment 41 Jerome Lanneluc CLA 2007-10-18 08:01:58 EDT
Created attachment 80654 [details]
Proposed API version 5

Hopefully this new version addresses issues raised by Markus.
Comment 42 Jerome Lanneluc CLA 2007-10-19 10:20:31 EDT
If everyone is happy with the latest API proposal, then I will release the corresponding implementation next week.
Comment 43 Leho Nigul CLA 2007-10-19 11:24:41 EDT
For IJavaElementDelta with regards to annotations, is that possible to provide more granular delta information? Such as which particular annotation got added/removed/modified? That will be very useful for the scenario where we have many annotations defined on certain java element
Comment 44 Jerome Lanneluc CLA 2007-10-19 12:39:19 EDT
(In reply to comment #43)
> For IJavaElementDelta with regards to annotations, is that possible to provide
> more granular delta information? Such as which particular annotation got
> added/removed/modified? That will be very useful for the scenario where we have
> many annotations defined on certain java element
> 
That's more work :-) But I'll try to come up with a proposal next week.
Comment 45 Leho Nigul CLA 2007-10-19 15:28:43 EDT
Hi Jerome, few more questions :)

1) Java annotations have a notion of scope (target), for example certain annotation can be defined to be relevant only in the context of a method. I don't think JDT checks for this information now, is that in plan to do that? If it is, 
what API would you use to see if particular IAnnotation is in the valid scope.

2) About the getNameRange() method, if I have something like that in code : @Stateless(name="test") , will this method
return the source range only for "Stateless" ? If I want to get the source for the whole annotation (including member value pairs), should I just call IAnnotation.getSource() ?

3) Question about handling "invalid input", if I have something like that in the source @Stateless(name=) and I
call getMemberValuePairs() , what will I get back? 
Comment 46 Philipe Mulet CLA 2007-10-19 17:50:43 EDT
Re: (1) in comment 45
I think the best way to find this out is to switch to using DOM AST bindings. The model is never going to be able to tackle these. Some bridging from annotation elements to DOM counterparts may be useful here.
Comment 47 Jerome Lanneluc CLA 2007-10-22 10:42:51 EDT
(In reply to comment #45)
> Hi Jerome, few more questions :)
> 
> 1) Java annotations have a notion of scope (target), for example certain
> annotation can be defined to be relevant only in the context of a method. I
> don't think JDT checks for this information now, is that in plan to do that? If
> it is, 
> what API would you use to see if particular IAnnotation is in the valid scope.
This information needs resolution and the Java model is based on source only and does not do resolution. So as Philippe said, you will need to use the DOM/AST APIs (see ASTParser.createAST(...) and ASTParser.setResolveBinding(...)).

> 2) About the getNameRange() method, if I have something like that in code :
> @Stateless(name="test") , will this method
> return the source range only for "Stateless" ? 
Yes

> If I want to get the source for
> the whole annotation (including member value pairs), should I just call
> IAnnotation.getSource() ?
Yes

> 3) Question about handling "invalid input", if I have something like that in
> the source @Stateless(name=) and I
> call getMemberValuePairs() , what will I get back? 
We will do our best to return a Java element that is as close as possible to the source. Unfortunately our parser recovery is not perfect yet. See bug 130778 for more details. So in the case you are giving, no IAnnotation will be returned.

Comment 48 Jerome Lanneluc CLA 2007-10-22 13:11:54 EDT
Created attachment 80891 [details]
Proposed API version 6

(In reply to comment #43)
> For IJavaElementDelta with regards to annotations, is that possible to provide
> more granular delta information? Such as which particular annotation got
> added/removed/modified? That will be very useful for the scenario where we have
> many annotations defined on certain java element

This new API proposal adds IJavaElementDelta#getAnnotationDeltas(). This is a list of added/removed/modified annotations.
Comment 49 Jerome Lanneluc CLA 2007-10-23 11:19:09 EDT
Created attachment 80963 [details]
Proposed API version 7

It looks like I forgot about binding keys for annotations. This new API proposal adds IAnnotation#getKey() and updates IBinding#getKey().
Comment 50 Jerome Lanneluc CLA 2007-10-23 11:28:56 EDT
If there is no strong objection, I will release the corresponding implementation tomorrow so that we have something for 3.4M3 (as per JDT/Core plan). 
Comment 51 Markus Keller CLA 2007-10-23 12:24:13 EDT
Why do we need IAnnotation#getKey()? AFAIK, the other #getKey() methods were only introduced as a way to piggyback resolved generic type information from references resolved by codeSelect(..). But annotations are never generic.

If you really think you should add IAnnotation#getKey(), then you should probably also add IPackageFragment#getKey() for consistency. CompilationUnit.findDeclaringNode(String) should also be updated then.

No objection against releasing to HEAD from my part.
Comment 52 Jerome Lanneluc CLA 2007-10-23 12:56:09 EDT
People CC'ed on this bug might also want to comment on bug 155013 comment 18.
Comment 53 Jerome Lanneluc CLA 2007-10-23 17:12:53 EDT
Created attachment 80998 [details]
Proposed API version 8

(In reply to comment #51)
> Why do we need IAnnotation#getKey()? [...]
You are right. This is not needed.
Comment 54 Markus Keller CLA 2007-10-24 06:10:02 EDT
Sorry, I was too quick with my comment 51:
#getKey() is required to find the corresponding declaration in the AST.
Please take v7 again, but add the annotation case to CompilationUnit.findDeclaringNode(String).
Comment 55 Jerome Lanneluc CLA 2007-10-24 09:24:14 EDT
(In reply to comment #54)
> Sorry, I was too quick with my comment 51:
> #getKey() is required to find the corresponding declaration in the AST.
> Please take v7 again, but add the annotation case to
> CompilationUnit.findDeclaringNode(String).
> 
Unfortunately CompilationUnit.findDeclaringNode(String) doesn't work with unresolved binding keys (see bug 207300). So IAnnotation#getKey() cannot be added before bug 207300 is fixed. I entered bug 207301 to remind us to add this.
Comment 56 Jerome Lanneluc CLA 2007-10-24 09:44:16 EDT
Created attachment 81058 [details]
Implementation corresponding to proposed API version 8
Comment 57 Jerome Lanneluc CLA 2007-10-24 09:51:18 EDT
Implementation released for 3.4M3.
Comment 58 Jerome Lanneluc CLA 2007-10-24 09:56:30 EDT
*** Bug 106108 has been marked as a duplicate of this bug. ***
Comment 59 David Audel CLA 2007-10-30 08:03:40 EDT
Verified for 3.4M3 using I20071029-0010 build.
Comment 60 Tom Mutdosch CLA 2007-11-20 13:59:17 EST
This works very well, thanks!  One question that arose from some of the comments.  What really is the best way to write annotations to a compilation unit?  It would be nice if there was some way to build up a model of Annotations and set them on the compilation unit.  As it is, I am constructing org.eclipse.jdt.core.dom.Annotation elements and passing these to a utility which will end up writing them to the compilation unit contents.  Is there a better way to add/modify annotations on a Java file?
Comment 61 Martin Aeschlimann CLA 2007-11-21 03:56:38 EST
To modify Java source we have the AST rewriter. Have a look at class 'ASTRewrite'. There's also an article on www.eclipse.org: http://www.eclipse.org/articles/Article-JavaCodeManipulation_AST/index.html
Comment 62 Andrew Mak CLA 2007-11-21 15:30:40 EST
Hi,

I am experimenting with the annotations API in eclipse 3.4 M3; specifically I've a IJavaElementChangeListener which I am using to listen for annotation add/remove/change events.  This seems to work fine when my project does not have an annotation processor configured in my project properties (under Java Compiler > Annotation Processing > Factory Path).  However, when I configure my project to use a custom annotation processor, I find that my listener no longer receives any annotation events.  Is this behavior by design or is there something I'm missing?  Thanks.
Comment 63 Leho Nigul CLA 2007-11-21 15:54:22 EST
RE62:
I already opened a defect on that issue --> https://bugs.eclipse.org/bugs/show_bug.cgi?id=210310  

I guess you can add your vote there :)
Comment 64 Jerome Lanneluc CLA 2007-12-05 12:03:01 EST
*** Bug 149074 has been marked as a duplicate of this bug. ***