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