View Javadoc

1   /*
2    * $Id: MetaAnnotationTypeFilter.java 20813 2010-12-21 11:37:48Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  package org.mule.util.scan.annotations;
11  
12  import java.io.IOException;
13  import java.io.InputStream;
14  import java.lang.annotation.Annotation;
15  import java.net.URL;
16  
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  import org.objectweb.asm.AnnotationVisitor;
20  import org.objectweb.asm.ClassReader;
21  
22  /**
23   * Will filter for a meta annotation type specified as the annotation class.  Meta annotations are annotations on other
24   * annotations.  this filter allows discovery of annotations on a class that have the same meta annotation.
25   */
26  public class MetaAnnotationTypeFilter implements AnnotationFilter
27  {
28      /**
29       * logger used by this class
30       */
31      protected transient final Log logger = LogFactory.getLog(MetaAnnotationTypeFilter.class);
32  
33      private Class<? extends Annotation> annotation;
34  
35      private ClassLoader classLoader;
36  
37      /**
38       * Creates an Meta Annotation Filter that look for Meta annotation on an
39       * annotation class
40       *
41       * @param annotation the annotation class to read
42       */
43      public MetaAnnotationTypeFilter(Class<? extends Annotation> annotation, ClassLoader classLoader)
44      {
45          this.annotation = annotation;
46          this.classLoader = classLoader;
47      }
48  
49      /**
50       * Creates an Meta Annotation Filter that look for Meta annotation on an annotation class. This constructor
51       * will cause the class reading to read from the System clssloader
52       * @param annotation the annotation class to read
53       */
54      public MetaAnnotationTypeFilter(Class<? extends Annotation> annotation)
55      {
56          this.annotation = annotation;
57          classLoader = Thread.currentThread().getContextClassLoader();
58      }
59  
60      public boolean accept(AnnotationInfo info)
61      {
62          try
63          {
64              URL classUrl = getClassURL(info.getClassName());
65              if (classUrl == null)
66              {
67                  logger.debug("Failed to load annotation class: " + info);
68                  return false;
69              }
70  
71              InputStream classStream = classUrl.openStream();
72              ClassReader r = new ClosableClassReader(classStream);
73  
74              MetaAnnotationScanner scanner = new MetaAnnotationScanner(new AnnotationTypeFilter(annotation));
75              r.accept(scanner, 0);
76  
77              return scanner.getClassAnnotations().size() == 1;
78          }
79          catch (IOException e)
80          {
81              logger.debug(e);
82              return false;
83          }
84      }
85  
86      private class MetaAnnotationScanner extends AnnotationsScanner
87      {
88          public MetaAnnotationScanner(AnnotationFilter filter)
89          {
90              super(filter);
91          }
92  
93          @Override
94          public AnnotationVisitor visitAnnotation(final String desc, final boolean visible)
95          {
96              currentAnnotation = new AnnotationInfo();
97              currentAnnotation.setClassName(getAnnotationClassName(desc));
98              if (log.isDebugEnabled())
99              {
100                 log.debug("Annotation: " + getAnnotationClassName(desc));
101             }
102 
103             // are we processing anything currently?
104             if (currentlyProcessing.nextSetBit(0) < 0)
105             {
106                 // no, this is a meta annotation
107                 currentlyProcessing.set(PROCESSING_CLASS);
108             }
109 
110             return this;
111         }
112 
113     }
114 
115     public URL getClassURL(String className)
116     {
117         String resource = className.replace(".", "/") + ".class";
118         return classLoader.getResource(resource);
119     }
120 }