View Javadoc

1   /*
2    * $Id: MetaAnnotationTypeFilter.java 20321 2010-11-24 15:21:24Z dfeist $
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 annotation class
39       * @param annotation the annotation class to read
40       * @param basepath the base path of the location of the class. Specifying this will be more
41       * reliable in applications that use Multiple classloaders since ASM uses the system classloader
42       * to read classes and thus ignores child classloaders.  The basepath should also start with a scheme,
43       * usually file: or jar:
44       */
45      public MetaAnnotationTypeFilter(Class<? extends Annotation> annotation, ClassLoader classLoader)
46      {
47          this.annotation = annotation;
48          this.classLoader = classLoader;
49      }
50  
51      /**
52       * Creates an Meta Annotation Filter that look for Meta annotation on an annotation class. This constructor
53       * will cause the class reading to read from the System clssloader
54       * @param annotation the annotation class to read
55       */
56      public MetaAnnotationTypeFilter(Class<? extends Annotation> annotation)
57      {
58          this.annotation = annotation;
59          classLoader = Thread.currentThread().getContextClassLoader();
60      }
61  
62      public boolean accept(AnnotationInfo info)
63      {
64          try
65          {
66              URL classUrl = getClassURL(info.getClassName());
67              if (classUrl == null)
68              {
69                  logger.debug("Failed to load annotation class: " + info);
70                  return false;
71              }
72              
73              InputStream classStream = classUrl.openStream();
74              ClassReader r = new ClosableClassReader(classStream);
75            
76              MetaAnnotationScanner scanner = new MetaAnnotationScanner(new AnnotationTypeFilter(annotation));
77              r.accept(scanner, 0);
78  
79              return scanner.getClassAnnotations().size() == 1;
80          }
81          catch (IOException e)
82          {
83              logger.debug(e);
84              return false;
85          }
86      }
87  
88      private class MetaAnnotationScanner extends AnnotationsScanner
89      {
90          public MetaAnnotationScanner(AnnotationFilter filter)
91          {
92              super(filter);
93          }
94  
95          @Override
96          public AnnotationVisitor visitAnnotation(final String desc, final boolean visible)
97          {
98              currentAnnotation = new AnnotationInfo();
99              currentAnnotation.setClassName(getAnnotationClassName(desc));
100             if (log.isDebugEnabled())
101             {
102                 log.debug("Annotation: " + getAnnotationClassName(desc));
103             }
104 
105             // are we processing anything currently?
106             if (currentlyProcessing.nextSetBit(0) < 0)
107             {
108                 // no, this is a meta annotation
109                 currentlyProcessing.set(PROCESSING_CLASS);
110             }
111 
112             return this;
113         }
114 
115     }
116 
117     public URL getClassURL(String className)
118     {
119         String resource = className.replace(".", "/") + ".class";
120         return classLoader.getResource(resource);
121     }
122 }