NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed. (sponsored)
In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.
Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.
Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Today I'm going to spend more time detailing how you can traverse elements in the mirror API to derive when they have annotations, not to mention what other elements they may have associated with them.
Declarations vs. Types
There are two core APIs in apt that seem remarkably similar - the Types API and the Declaration API. The distinction between declarations and types can be hard to understand, but is vitally important to understand when processing with apt. All of the documentation on apt is very careful to note the difference between declarations and types, and it would be a pity if I didn't do the same here. The mirror API has these two concepts (declaration and type) that seem quite similar. Declarations are the lion's share of the API, and represent the actual source being processed by apt. If you write this code:
publicclass HelloWorld {
public java.util.Set<java.lang.String> getStrings() { ... }
}
... apt is going to provide a
com.sun.mirror.apt.declaration.ClassDeclaration
object for that 'HelloWorld' declaration. There would also be a
com.sun.mirror.apt.declaration.MethodDeclaration
for the
getStrings()
method (available via
ClassDeclaration.getMethods()
). Both of these interfaces extend
com.sun.mirror.apt.declaration.Declaration
. However, the
return type
of the method
getStrings()
is
not
an instance of
Declaration
- instead it is an instance of
com.sun.mirror.apt.type.TypeMirror
. So, what is the difference? For one thing, types simply do not always correlate to a declaration - some examples include arrays, primitives, the void return type, and now that we have them, we can't forget Generics. After all, as far as Java developers are concerned, there
is no
declaration for the int type, or for the void return type. Generics complicate matters even futher, because the usage of a type that
has a declaration
differs from the declaration itself. In our example above,
java.util.Set<java.lang.String>
doesn't relate directly to the
java.util.Set
class declaration - after all, we are defining an additional piece of information in this case - the type parameters for the generics. The way the documentation describes it, a
TypeMirror
represents the use of some construct in the code. Being more specific for the case where you are dealing with classes referring to other classes (or interfaces) - a
com.sun.mirror.apt.type.DeclaredType
represents a single use (such as a method return type) of a
com.sun.mirror.apt.declaration.TypeDeclaration
. Relying on that piece of information, here is a block of code that walks the object hierarchy for our little pseudo-class above (note, I am using some less that attractive coding practices simply so I can show the expected values for this particular case):
AnnotationProcessorEnvironment environment = // ... get from somewhere
// get class declaration for 'HelloWorld' class.
ClassDeclaration classDecl = (ClassDeclaration)environment.getTypeDeclaration("HelloWorld");
// get the first method declaration - 'getStrings()' declaration.
MethodDeclaration decl = classDecl.getMethods().iterator().next();
TypeMirror returnTypeMirror = decl.getReturnType();
// in this case we KNOW that it's a ClassType (for Set<String>)
ClassType setType = (ClassType)returnTypeMirror;
// get the DECLARATION of the set type (correlates to java/util/Set.class)
ClassDeclaration setDeclaration = setType.getDeclaration();
Collection<TypeMirror> typeArgs = classType.getActualTypeArguments();
// get the first type argument - 'String' in this case
TypeMirror firstTypeArg = typeArgs.iterator().next();
ClassType stringType = (ClassType) firstTypeArg;
ClassDeclaration stringDeclaration = stringType.getDeclaration();
Incidentally, the
getSuperclass()
method on
ClassDeclaration
returns a
ClassType
. This may seem confusing at first, but the more you think about it, the more it makes sense. Here is an example where superclass semantics require a type, and not simply a declaration:
Notice how the superclass definition is given particular type parameters.
Declaration API
The declaration API is fairly hefty - and rather than go to all the trouble of trying to describe each part here - I'll use the 'picture worth 1000 words' excuse, and SHOW you the API.
As can be seen by the above diagram, the API is
very
rich and granular. While some of it is self-explanatory, there are a few interesting structures I thought merited descriptions.
It can be confusing at first glance that nearly everything extends
MemberDeclaration
(excluding packages, parameters and type parameters) - after all
MemberDeclarations
as the terminology suggests, represent a member of a declared type. The thought would be this would include methods, constructors, fields and the like. It turns out, however, that types being member declarations themselves is correct, since we have inner-classes. It just so happens that the method
TypeDeclaration getDeclaringType()
will return null if the
MemberDeclaration
it is called on is a top-level
TypeDeclaration
itself.
Note that there is a
ParameterDeclaration
and
a
TypeParameterDeclaration
- the distinction is simply for generics - the former is a method declaration parameter (or constructor declaration parameter), the latter is a generic type parameter. Because they are different in nature, they have different declaration APIs.
Declarations Util
The
com.sun.mirror.util.Declarations
API has two handy methods for determining the context of declarations when dealing with the world of inheritence. The two methods are
boolean hides(MemberDeclaration, MemberDeclaration)
and
boolean overrides(MethodDeclaration, MethodDeclaration)
. Both of these methods take a first parameter (the sub-declaration) to compare to the second parameter (the super-declaration). The former is a general-case where method overriding or field-masking can cause a certain member to be hidden. The latter is specifically involves determining method overrides.
The Declarations utils are available through the AnnotationProcessorEnvironment.getDeclarationUtils method.
Types API
The types API is similar to the declaration API - but try not to think of them as parallel. Remember - the types API is specifically designed for the usage of types in another declaration. Here is another 1000 word picture:
You can already see that the hierarchy is much smaller. It turns out the problem domain is smaller. In this case there are only four different types of type mirror - primitive types (references to short, int, byte, char, etc.), reference types (references to other classes, arrays, etc.), void types (only applies to void return types), and wildcard types (only applies to the '?' element for generics).
Types Util
The types utility library
com.sun.mirror.util.Types
is much less trivial from the
Declarations
utility class. While some of it is in fact similar in nature to the
Declarations
class (
boolean isSubtype(TypeMirror, TypeMirror)
),
boolean isAssignable(TypeMirror, TypeMirror)
- much of the class acts like a 'TypeMirrorFactory'. These 'factory' style methods are important because it is often handy to check methods/fields/constructors/generics/whatever-else for equality to certain types. Some examples:
ArrayType getArrayType(TypeMirror)
- Gets an array that holds elements represented by the
TypeMirror
parameter. So, if
TypeMirror
represents the
String
class, then it would return an
ArrayType
representing the
String[]
construct.
VoidType getVoidType()
- The special void return type.
PrimitiveType getPrimitiveType(PrimitiveType.Kind)
- Returns the PrimitiveType object representing the selected primitive type from the
PrimitiveType.Kind
enumeration.
TypeMirror getErasure(TypeMirror)
- This gets the runtime resolution of a type mirror reference once the generics have been 'erased' by the compiler.
DeclaredType getDeclaredType(...)
- The two
getDeclaredType()
methods are convenient for producing DeclaredType references. For instance, the example they give in the documentation produces a Set<String> DeclaredType (which can be used for equality checks later), and it does so in multiple passes:
I can't give the best examples for using all of these utility methods - simply knowing that they are there should give you the leverage you need when it comes time to check some method/field for the right type when performing annotation processing.
The types utilities are available through the AnnotationProcessorEnvironment.getTypesUtils() method.
Annotation Mirrors
Because apt is a tool specifically designed for annotation processing, it comes with some special facilities for annotations - namely the
com.sun.mirror.declaration.AnnotationMirror
class. This annotation mirror effectively represents an 'instance' of an annotation. The usage of an annotation on a particular element, values and all. I don't plan on re-hashing the annotation mirror element here, as I showed it briefly in my previous tip. Just be aware that annotation mirrors can be retrieved for
any
class that implements
com.sun.mirror.declaration.Declaration
.
Processing with Visitors
Most of the processing in the world of apt is done through the magic of the visitor pattern. Up-to-this-point I have avoided using it because I didn't want to introduce any unnecessary complexities to the code. No longer. The power of the visitor API in apt is two-fold. First, the algorithm for traversing nodes (declarations and types) is abstracted away (you don't have to write it) - and second, you don't have to perform any casting in your code - it does all of the introspection for you with the magic of polymorphism. For instance, let's start small with the TypeVisitor API. The
com.sun.mirror.util.TypeVisitor
interface defines a ton of 'visit' methods that are invoked by a
TypeMirror
when it is 'visited'. You can (and should) subclass the
com.sun.mirror.util.SimpleTypeVisitor
if you want to implement your own visitor. First, this class stubs all of the interface methods, making the implementation for you much simpler. Second, some of the 'visit' methods don't relate directly to a concrete type (e.g. visitDeclaredType(DeclaredType t)) - these methods can be handy if you want to visit all elements that are a DeclaredType. The
SimpleTypeVisitor
API delegates up the type-hierarchy - for example,
visitClassType(ClassType t)
does nothing but delegate up to visitDeclaredType(DeclaredType t). This delegation is not part of the TypeMirror elements themselves. To invoke a type visitor given an unknown type mirror, simply call the accept method:
The type mirror in question will then invoke the right 'visit' method, and you can process accordingly.
Declarations are similar to types, although they potentially involve more digging (since classes contain methods/fields/constructors/other classes). There is a special static utility class -
com.sun.mirror.util.DeclarationVisitors
that can help with this process. The
DeclarationVisitiors
class can create what is called a
DeclarationScanner
which is really just a special implementation of the
DeclarationVisitor
API that will respond to a type visit by iterating it's child declarations (e.g. members) and invoking the correct visit method for each on its contained visitor. In other words, it is a processing algorithm for iterating a declaration hierarchy. In the previous tip, I used a special method on the
AnnotationProcessorEnvironment
class -
getDeclarationsAnnotatedWith(AnnotationTypeDeclaration)
. Let's say for the moment that we didn't have this special method. Here is how we could implement the exact same behavior using the visitor pattern:
package com.javalobby.tnt.apt;
import java.util.*;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.AnnotationType;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.util.*;
publicclass NoteAnnotationProcessor implements AnnotationProcessor {
private AnnotationProcessorEnvironment environment;
private TypeDeclaration noteDeclaration;
private DeclarationVisitor declarationVisitor;
public NoteAnnotationProcessor(AnnotationProcessorEnvironment env) {
environment = env;
// get the annotation type declaration for our 'Note' annotation.
noteDeclaration = environment
.getTypeDeclaration("com.javalobby.tnt.annotation.Note");
declarationVisitor = new AllDeclarationsVisitor();
}
publicvoid process() {
Collection<TypeDeclaration> declarations = environment.getTypeDeclarations();
// Note here we use a helper method to create a declaration scanner for our
// visitor, and a no-op visitor.
DeclarationVisitor scanner = DeclarationVisitors
.getSourceOrderDeclarationScanner(declarationVisitor,
DeclarationVisitors.NO_OP);
for (TypeDeclaration declaration : declarations) {
declaration.accept(scanner); // invokes the processing on the scanner.
}
}
privateclass AllDeclarationsVisitor extends SimpleDeclarationVisitor {
@Override
publicvoid visitDeclaration(Declaration arg0) {
Collection<AnnotationMirror> annotations = arg0.getAnnotationMirrors();
for (AnnotationMirror mirror : annotations) {
// if the mirror in this iteration is for our note declaration...
if (mirror.getAnnotationType().getDeclaration().equals(noteDeclaration)) {
// print out the goodies.
SourcePosition position = mirror.getPosition();
Map<AnnotationTypeElementDeclaration, AnnotationValue> values = mirror
.getElementValues();
System.out.println("Declaration: " + noteDeclaration.toString());
System.out.println("Position: " + position);
System.out.println("Values:");
for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : values
.entrySet()) {
AnnotationTypeElementDeclaration elemDecl = entry.getKey();
AnnotationValue value = entry.getValue();
System.out.println(" " + elemDecl + "=" + value);
}
}
}
}
}
}
So now you have some idea on how to get started understanding the iteration/processing patterns when dealing with the Mirror API. The final step is to understand how to properly respond to annotations when processing. Next time I will introduce the
com.sun.mirror.apt.Messager
, the
com.sun.mirror.apt.Filer
, the concept of Apt rounds, and then, as I usually do, I'll pick up some left-overs to add food-for-thought.
Apt: More Compile-Time Annotation Processing with Java
At 5:44 PM on Mar 23, 2005, R.J. Lorimer wrote:
Fresh Jobs for Developers Post a job opportunity
Part 2
Welcome back to my Java Annotation Processing Tool tip-series. If you haven't already, please see my previous tip:APT: Compile-Time Annotation Processing with Java
Today I'm going to spend more time detailing how you can traverse elements in the mirror API to derive when they have annotations, not to mention what other elements they may have associated with them.
Declarations vs. Types
There are two core APIs in apt that seem remarkably similar - the Types API and the Declaration API. The distinction between declarations and types can be hard to understand, but is vitally important to understand when processing with apt. All of the documentation on apt is very careful to note the difference between declarations and types, and it would be a pity if I didn't do the same here. The mirror API has these two concepts (declaration and type) that seem quite similar. Declarations are the lion's share of the API, and represent the actual source being processed by apt. If you write this code:
public class HelloWorld { public java.util.Set<java.lang.String> getStrings() { ... } }... apt is going to provide a
com.sun.mirror.apt.declaration.ClassDeclarationobject for that 'HelloWorld' declaration. There would also be acom.sun.mirror.apt.declaration.MethodDeclarationfor thegetStrings()method (available viaClassDeclaration.getMethods()). Both of these interfaces extendcom.sun.mirror.apt.declaration.Declaration. However, the return type of the methodgetStrings()is not an instance ofDeclaration- instead it is an instance ofcom.sun.mirror.apt.type.TypeMirror. So, what is the difference? For one thing, types simply do not always correlate to a declaration - some examples include arrays, primitives, the void return type, and now that we have them, we can't forget Generics. After all, as far as Java developers are concerned, there is no declaration for the int type, or for the void return type. Generics complicate matters even futher, because the usage of a type that has a declaration differs from the declaration itself. In our example above,java.util.Set<java.lang.String>doesn't relate directly to thejava.util.Setclass declaration - after all, we are defining an additional piece of information in this case - the type parameters for the generics. The way the documentation describes it, aTypeMirrorrepresents the use of some construct in the code. Being more specific for the case where you are dealing with classes referring to other classes (or interfaces) - acom.sun.mirror.apt.type.DeclaredTyperepresents a single use (such as a method return type) of acom.sun.mirror.apt.declaration.TypeDeclaration. Relying on that piece of information, here is a block of code that walks the object hierarchy for our little pseudo-class above (note, I am using some less that attractive coding practices simply so I can show the expected values for this particular case):AnnotationProcessorEnvironment environment = // ... get from somewhere // get class declaration for 'HelloWorld' class. ClassDeclaration classDecl = (ClassDeclaration)environment.getTypeDeclaration("HelloWorld"); // get the first method declaration - 'getStrings()' declaration. MethodDeclaration decl = classDecl.getMethods().iterator().next(); TypeMirror returnTypeMirror = decl.getReturnType(); // in this case we KNOW that it's a ClassType (for Set<String>) ClassType setType = (ClassType)returnTypeMirror; // get the DECLARATION of the set type (correlates to java/util/Set.class) ClassDeclaration setDeclaration = setType.getDeclaration(); Collection<TypeMirror> typeArgs = classType.getActualTypeArguments(); // get the first type argument - 'String' in this case TypeMirror firstTypeArg = typeArgs.iterator().next(); ClassType stringType = (ClassType) firstTypeArg; ClassDeclaration stringDeclaration = stringType.getDeclaration();Incidentally, the
getSuperclass()method onClassDeclarationreturns aClassType. This may seem confusing at first, but the more you think about it, the more it makes sense. Here is an example where superclass semantics require a type, and not simply a declaration:public class MyGenericsSuperclass<E> { ... } public class MyGenericsSubclass extends MyGenericsSuperclass<String> { ... }Notice how the superclass definition is given particular type parameters.
Declaration API
The declaration API is fairly hefty - and rather than go to all the trouble of trying to describe each part here - I'll use the 'picture worth 1000 words' excuse, and SHOW you the API.
As can be seen by the above diagram, the API is very rich and granular. While some of it is self-explanatory, there are a few interesting structures I thought merited descriptions.
It can be confusing at first glance that nearly everything extends
MemberDeclaration(excluding packages, parameters and type parameters) - after allMemberDeclarationsas the terminology suggests, represent a member of a declared type. The thought would be this would include methods, constructors, fields and the like. It turns out, however, that types being member declarations themselves is correct, since we have inner-classes. It just so happens that the methodTypeDeclaration getDeclaringType()will return null if theMemberDeclarationit is called on is a top-levelTypeDeclarationitself.Note that there is a
ParameterDeclarationand aTypeParameterDeclaration- the distinction is simply for generics - the former is a method declaration parameter (or constructor declaration parameter), the latter is a generic type parameter. Because they are different in nature, they have different declaration APIs.Declarations Util
The
com.sun.mirror.util.DeclarationsAPI has two handy methods for determining the context of declarations when dealing with the world of inheritence. The two methods areboolean hides(MemberDeclaration, MemberDeclaration)andboolean overrides(MethodDeclaration, MethodDeclaration). Both of these methods take a first parameter (the sub-declaration) to compare to the second parameter (the super-declaration). The former is a general-case where method overriding or field-masking can cause a certain member to be hidden. The latter is specifically involves determining method overrides.The Declarations utils are available through the AnnotationProcessorEnvironment.getDeclarationUtils method.
Types API
The types API is similar to the declaration API - but try not to think of them as parallel. Remember - the types API is specifically designed for the usage of types in another declaration. Here is another 1000 word picture:
You can already see that the hierarchy is much smaller. It turns out the problem domain is smaller. In this case there are only four different types of type mirror - primitive types (references to short, int, byte, char, etc.), reference types (references to other classes, arrays, etc.), void types (only applies to void return types), and wildcard types (only applies to the '?' element for generics).
Types Util
The types utility library
com.sun.mirror.util.Typesis much less trivial from theDeclarationsutility class. While some of it is in fact similar in nature to theDeclarationsclass (boolean isSubtype(TypeMirror, TypeMirror)),boolean isAssignable(TypeMirror, TypeMirror)- much of the class acts like a 'TypeMirrorFactory'. These 'factory' style methods are important because it is often handy to check methods/fields/constructors/generics/whatever-else for equality to certain types. Some examples:ArrayType getArrayType(TypeMirror)- Gets an array that holds elements represented by theTypeMirrorparameter. So, ifTypeMirrorrepresents theStringclass, then it would return anArrayTyperepresenting theString[]construct.VoidType getVoidType()- The special void return type.PrimitiveType getPrimitiveType(PrimitiveType.Kind)- Returns the PrimitiveType object representing the selected primitive type from thePrimitiveType.Kindenumeration.TypeMirror getErasure(TypeMirror)- This gets the runtime resolution of a type mirror reference once the generics have been 'erased' by the compiler.DeclaredType getDeclaredType(...)- The twogetDeclaredType()methods are convenient for producing DeclaredType references. For instance, the example they give in the documentation produces a Set<String> DeclaredType (which can be used for equality checks later), and it does so in multiple passes:TypeDeclaration setDecl = environment.getTypeDeclaration("java.util.Set"); TypeDeclaration stringDecl = environment.getTypeDeclaration("java.lang.String"); DeclaredType stringType = Types.getDeclaredType(stringDecl, null); // String DeclaredType setOfStrings = Types.getDeclaredType(setDecl, stringType); // Set<String>I can't give the best examples for using all of these utility methods - simply knowing that they are there should give you the leverage you need when it comes time to check some method/field for the right type when performing annotation processing.
The types utilities are available through the AnnotationProcessorEnvironment.getTypesUtils() method.
Annotation Mirrors
Because apt is a tool specifically designed for annotation processing, it comes with some special facilities for annotations - namely the
com.sun.mirror.declaration.AnnotationMirrorclass. This annotation mirror effectively represents an 'instance' of an annotation. The usage of an annotation on a particular element, values and all. I don't plan on re-hashing the annotation mirror element here, as I showed it briefly in my previous tip. Just be aware that annotation mirrors can be retrieved for any class that implementscom.sun.mirror.declaration.Declaration.Processing with Visitors
Most of the processing in the world of apt is done through the magic of the visitor pattern. Up-to-this-point I have avoided using it because I didn't want to introduce any unnecessary complexities to the code. No longer. The power of the visitor API in apt is two-fold. First, the algorithm for traversing nodes (declarations and types) is abstracted away (you don't have to write it) - and second, you don't have to perform any casting in your code - it does all of the introspection for you with the magic of polymorphism. For instance, let's start small with the TypeVisitor API. The
com.sun.mirror.util.TypeVisitorinterface defines a ton of 'visit' methods that are invoked by aTypeMirrorwhen it is 'visited'. You can (and should) subclass thecom.sun.mirror.util.SimpleTypeVisitorif you want to implement your own visitor. First, this class stubs all of the interface methods, making the implementation for you much simpler. Second, some of the 'visit' methods don't relate directly to a concrete type (e.g. visitDeclaredType(DeclaredType t)) - these methods can be handy if you want to visit all elements that are a DeclaredType. TheSimpleTypeVisitorAPI delegates up the type-hierarchy - for example,visitClassType(ClassType t)does nothing but delegate up to visitDeclaredType(DeclaredType t). This delegation is not part of the TypeMirror elements themselves. To invoke a type visitor given an unknown type mirror, simply call the accept method:The type mirror in question will then invoke the right 'visit' method, and you can process accordingly.
Declarations are similar to types, although they potentially involve more digging (since classes contain methods/fields/constructors/other classes). There is a special static utility class -
com.sun.mirror.util.DeclarationVisitorsthat can help with this process. TheDeclarationVisitiorsclass can create what is called aDeclarationScannerwhich is really just a special implementation of theDeclarationVisitorAPI that will respond to a type visit by iterating it's child declarations (e.g. members) and invoking the correct visit method for each on its contained visitor. In other words, it is a processing algorithm for iterating a declaration hierarchy. In the previous tip, I used a special method on theAnnotationProcessorEnvironmentclass -getDeclarationsAnnotatedWith(AnnotationTypeDeclaration). Let's say for the moment that we didn't have this special method. Here is how we could implement the exact same behavior using the visitor pattern:package com.javalobby.tnt.apt; import java.util.*; import com.sun.mirror.apt.*; import com.sun.mirror.declaration.*; import com.sun.mirror.type.AnnotationType; import com.sun.mirror.type.TypeMirror; import com.sun.mirror.util.*; public class NoteAnnotationProcessor implements AnnotationProcessor { private AnnotationProcessorEnvironment environment; private TypeDeclaration noteDeclaration; private DeclarationVisitor declarationVisitor; public NoteAnnotationProcessor(AnnotationProcessorEnvironment env) { environment = env; // get the annotation type declaration for our 'Note' annotation. noteDeclaration = environment .getTypeDeclaration("com.javalobby.tnt.annotation.Note"); declarationVisitor = new AllDeclarationsVisitor(); } public void process() { Collection<TypeDeclaration> declarations = environment.getTypeDeclarations(); // Note here we use a helper method to create a declaration scanner for our // visitor, and a no-op visitor. DeclarationVisitor scanner = DeclarationVisitors .getSourceOrderDeclarationScanner(declarationVisitor, DeclarationVisitors.NO_OP); for (TypeDeclaration declaration : declarations) { declaration.accept(scanner); // invokes the processing on the scanner. } } private class AllDeclarationsVisitor extends SimpleDeclarationVisitor { @Override public void visitDeclaration(Declaration arg0) { Collection<AnnotationMirror> annotations = arg0.getAnnotationMirrors(); for (AnnotationMirror mirror : annotations) { // if the mirror in this iteration is for our note declaration... if (mirror.getAnnotationType().getDeclaration().equals(noteDeclaration)) { // print out the goodies. SourcePosition position = mirror.getPosition(); Map<AnnotationTypeElementDeclaration, AnnotationValue> values = mirror .getElementValues(); System.out.println("Declaration: " + noteDeclaration.toString()); System.out.println("Position: " + position); System.out.println("Values:"); for (Map.Entry<AnnotationTypeElementDeclaration, AnnotationValue> entry : values .entrySet()) { AnnotationTypeElementDeclaration elemDecl = entry.getKey(); AnnotationValue value = entry.getValue(); System.out.println(" " + elemDecl + "=" + value); } } } } } }So now you have some idea on how to get started understanding the iteration/processing patterns when dealing with the Mirror API. The final step is to understand how to properly respond to annotations when processing. Next time I will introduce the
com.sun.mirror.apt.Messager, thecom.sun.mirror.apt.Filer, the concept of Apt rounds, and then, as I usually do, I'll pick up some left-overs to add food-for-thought.Until next time,
R.J. Lorimer
rj -at- javalobby.org
http://www.coffee-bytes.com
2 replies so far (
Post your own)
Re: Apt: More Compile-Time Annotation Processing with Java
Nice article.I also like to use AOP to work with annotations a la:
http://www.almaer.com/blog/archives/000832.html
Cheers,
Dion Almaer
http://www.almaer.com/blog
Re: Apt: More Compile-Time Annotation Processing with Java
which API can i use to extract the annotation Type "Romote", "Remove" out of the following codepackage org.jboss.tutorial.stateful.bean;
import javax.ejb.Remote;
import javax.ejb.Remove;
import java.util.HashMap;
@Remote
public interface ShoppingCart
{
void buy(String product, int quantity);
HashMap getCartContents();
@Remove void checkout();
}
and also i have no idea how to use the method:
A getAnnotation(Class annotationType)
Returns the annotation of this declaration having the specified type.
thanks in advance