[jboss-dev-forums] [Design of POJO Server] - Using AnnotationEnvironment in Seam

alesj do-not-reply at jboss.com
Tue Aug 19 08:12:03 EDT 2008


I'll describe a bit how AnnotationEnvoroment works, where it comes from, ... 
but then it should be up to Seam guys to fully incorporate this into Seam's
component scanning / lookup.

AnnotationEnv API:

  | public interface AnnotationEnvironment
  | {
  |    /**
  |     * Does this annotation environment contain a class
  |     * which is annotated with annotation parameter.
  |     * This only applies to annotations for ElementType.TYPE level.
  |     *
  |     * This method should be used if we have no intention
  |     * to do real lookup of annotated classes, but we're
  |     * only interested in existance of the annotation.
  |     * e.g. deployment unit contains @Stateful EJBs
  |     *
  |     * @param annotation the annotation we're querying for
  |     * @return true if there exists a class with annotation param
  |     * @see #hasClassAnnotatedWith(Class annotation)
  |     */
  |    boolean hasClassAnnotatedWith(Class<? extends Annotation> annotation);
  | 
  |    /**
  |     * Does this annotation environment contain a class
  |     * which is annotated with annotation parameter.
  |     * This only applies to annotations for ElementType.TYPE level.
  |     *
  |     * This method should be used if we have no intention
  |     * to do real lookup of annotated classes, but we're
  |     * only interested in existance of the annotation.
  |     * e.g. deployment unit contains @Stateful EJBs
  |     *
  |     * @param annotationName the annotation name we're querying for
  |     * @return true if there exists a class with annotation param
  |     * @see #hasClassAnnotatedWith(Class annotation)
  |     */
  |    boolean hasClassAnnotatedWith(String annotationName);
  | 
  |    /**
  |     * Get all classes annotated with annotation param.
  |     *
  |     * @param <A> the annotation type
  |     * @param annotation the annotation we're querying for
  |     * @return set of matching classes
  |     */
  |    <A extends Annotation> Set<Element<A, Class<?>>> classIsAnnotatedWith(Class<A> annotation);
  | 
  |    /**
  |     * Get all classes annotated with annotation param.
  |     *
  |     * @param annotationName the annotation name we're querying for
  |     * @return set of matching classes
  |     */
  |    Set<Element<Annotation, Class<?>>> classIsAnnotatedWith(String annotationName);
  | 
  |    /**
  |     * Get all classes who have some constructor annotated with annotation param.
  |     *
  |     * @param <A> the annotation type
  |     * @param annotation the annotation we're querying for
  |     * @return set of matching classes
  |     */
  |    <A extends Annotation> Set<Element<A, Constructor<?>>> classHasConstructorAnnotatedWith(Class<A> annotation);
  | 
  |    /**
  |     * Get all classes who have some constructor annotated with annotation param.
  |     *
  |     * @param annotationName the annotation name we're querying for
  |     * @return set of matching classes
  |     */
  |    Set<Element<Annotation, Constructor<?>>> classHasConstructorAnnotatedWith(String annotationName);
  | 
  |    /**
  |     * Get all classes who have some field annotated with annotation param.
  |     *
  |     * @param <A> the annotation type
  |     * @param annotation the annotation we're querying for
  |     * @return set of matching classes
  |     */
  |    <A extends Annotation> Set<Element<A, Field>> classHasFieldAnnotatedWith(Class<A> annotation);
  | 
  |    /**
  |     * Get all classes who have some field annotated with annotation param.
  |     *
  |     * @param annotationName the annotation name we're querying for
  |     * @return set of matching classes
  |     */
  |    Set<Element<Annotation, Field>> classHasFieldAnnotatedWith(String annotationName);
  | 
  |    /**
  |     * Get all classes who have some method annotated with annotation param.
  |     *
  |     * @param <A> the annotation type
  |     * @param annotation the annotation we're querying for
  |     * @return set of matching classes
  |     */
  |    <A extends Annotation> Set<Element<A, Method>> classHasMethodAnnotatedWith(Class<A> annotation);
  | 
  |    /**
  |     * Get all classes who have some method annotated with annotation param.
  |     *
  |     * @param annotationName the annotation name we're querying for
  |     * @return set of matching classes
  |     */
  |    Set<Element<Annotation, Method>> classHasMethodAnnotatedWith(String annotationName);
  | 
  |    /**
  |     * Get all classes who have some method's/constructor's parameter annotated with annotation param.
  |     *
  |     * @param <A> the annotation type
  |     * @param annotation the annotation we're querying for
  |     * @return set of matching classes
  |     */
  |    <A extends Annotation> Set<Element<A, AnnotatedElement>> classHasParameterAnnotatedWith(Class<A> annotation);
  | 
  |    /**
  |     * Get all classes who have some method's/constructor's parameter annotated with annotation param.
  |     *
  |     * @param annotationName the annotation name we're querying for
  |     * @return set of matching classes
  |     */
  |    Set<Element<Annotation, AnnotatedElement>> classHasParameterAnnotatedWith(String annotationName);
  | }
  | 
  | public interface Element<A extends Annotation, M extends AnnotatedElement>
  | {
  |    /**
  |     * Get the owner class name.
  |     *
  |     * Until we hit getOwner method the class should not be loaded.
  |     *
  |     * @return the owner classname
  |     */
  |    String getOwnerClassName();
  | 
  |    /**
  |     * Get the annotation owner class.
  |     *
  |     * @return the annotation owner class
  |     */
  |    Class<?> getOwner();
  | 
  |    /**
  |     * Get the annotation instance.
  |     *
  |     * @return the annotation instance
  |     */
  |    A getAnnotation();
  | 
  |    /**
  |     * Get the annotated element that holds the annotation.
  |     *
  |     * @return the annotated element instance
  |     */
  |    M getAnnotatedElement();
  | }
  | 
The API is pretty simple :-),
as can be seen it has to 'flavors',
one where you put direct annotation class as parameter,
the other one where you put annotation class name.

The Element has a few useful hooks,
and its impl detail is that it's completely lazy - 
it doesn't load the class or annotation until asked.

There is a flag on the annotation scanning deployer,
that allows for AnnotationEnvironment to already keep
the annotation instance gathered from Javassist lookup - 
meaning you don't even need to load the class to 
inspect annotation value.
e.g. you only need classname + annotation member values

When (annotation scanning) deployers are properly configured,
this is already the case in current JBoss5 trunk,
every deployment unit gets AnnotationEnvironment as an attachment.


  |       DeploymentUnit unit = getAttribute(context, DeploymentUnit.class.getName(), DeploymentUnit.class);
  |       AnnotationEnvironment env = unit.getAttachment(AnnotationEnvironment.class);
  | 

In the Seam case we would have to do a bit of 
hierarchy traversing to get all the AnnotationEnvironments,
from all deployment units, since we only have web deployment unit,
in the ServletContext attributes.


  | public class JBossSeamListener extends SeamListener
  | {
  |    public void contextInitialized(ServletContextEvent event)
  |    {
  |       // TODO - enable some MC scanning notion in Seam
  |       super.contextInitialized(event);
  |       
  |       ServletContext context = event.getServletContext();
  |       Kernel kernel = getAttribute(context, Kernel.class.getName(), Kernel.class);
  |       DeploymentUnit unit = getAttribute(context, DeploymentUnit.class.getName(), DeploymentUnit.class);
  | 

Looking at the ComponentDeploymentHandler::handle

  |    public void handle(String name, ClassLoader classLoader)
  |    {
  |       if (name.endsWith(".class")) 
  |       {
  |          String classname = filenameToClassname(name);
  |          String filename = componentFilename(name);
  |          try 
  |          {
  |             ClassFile classFile = getClassFile(name, classLoader);
  |             boolean installable = ( hasAnnotation(classFile, Name.class) || classLoader.getResources(filename).hasMoreElements() )
  |                      && !"false".equals( getAnnotationValue(classFile, Install.class, "value") );
  |             if (installable) 
  |             {
  |                log.trace("found component class: " + name);
  |                classes.add( (Class<Object>) classLoader.loadClass(classname) );
  |             }
  | 
Looks like we should also do a bit more than just looking for @Name,
but for the @Install::value==false it should be just a simple Set intersection.
Where I don't see what exactly does "classLoader.getResources(filename).hasMoreElements() " do/help.

Pete & co., if you need any other info,
post it here. :-)

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4171242#4171242

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4171242



More information about the jboss-dev-forums mailing list