View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.uruma.util;
17  
18  import java.lang.annotation.Annotation;
19  import java.lang.reflect.Field;
20  import java.lang.reflect.Method;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.seasar.framework.beans.BeanDesc;
27  import org.seasar.framework.beans.PropertyDesc;
28  import org.seasar.framework.beans.factory.BeanDescFactory;
29  
30  /**
31   * アノテーションを持つクラスに対するユーティリティクラスです。<br />
32   * 
33   * @author y-komori
34   */
35  public class AnnotationUtil {
36      private static Map<ClassEntry, List<Field>> fieldCache = new HashMap<ClassEntry, List<Field>>();
37  
38      private static Map<ClassEntry, List<Method>> methodCache = new HashMap<ClassEntry, List<Method>>();
39  
40      private static Map<ClassEntry, List<PropertyDesc>> pdCache = new HashMap<ClassEntry, List<PropertyDesc>>();
41  
42      protected AnnotationUtil() {
43      }
44  
45      /**
46       * 特定のアノテーションが付加されたフィールドを取得します。<br />
47       * <p>
48       * <code>clazz</code> で指定されたクラスから <code>annotationClass</code>
49       * で指定されたアノテーションが付加された {@link Field} オブジェクトのリストを返します。<br />
50       * フィールドは、親クラスまでさかのぼってすべて検索されます。
51       * </p>
52       * 
53       * @param clazz
54       *            対象クラス
55       * @param annotationClass
56       *            対象アノテーション
57       * @return 見つかった {@link Field} オブジェクトのリスト
58       */
59      public static List<Field> getAnnotatedFields(final Class<?> clazz,
60              final Class<? extends Annotation> annotationClass) {
61          ClassEntry entry = new ClassEntry(clazz, annotationClass);
62          List<Field> result = fieldCache.get(entry);
63          if (result != null) {
64              return result;
65          } else {
66              result = new ArrayList<Field>();
67              BeanDesc desc = BeanDescFactory.getBeanDesc(clazz);
68              int fieldSize = desc.getFieldSize();
69              for (int i = 0; i < fieldSize; i++) {
70                  Field field = desc.getField(i);
71                  if (field.getAnnotation(annotationClass) != null) {
72                      result.add(field);
73                      fieldCache.put(entry, result);
74                  }
75              }
76              return result;
77          }
78      }
79  
80      /**
81       * 特定のアノテーションが付加されたメソッドを取得します。<br />
82       * <p>
83       * <code>clazz</code> で指定されたクラスから <code>annotationClass</code>
84       * で指定されたアノテーションが付加された {@link Method} オブジェクトのリストを返します。<br />
85       * メソッドは、親クラスまでさかのぼってすべて検索されます。
86       * </p>
87       * 
88       * @param clazz
89       *            対象クラス
90       * @param annotationClass
91       *            対象アノテーション
92       * @return 見つかったメソッドのリスト
93       */
94      public static List<Method> getAnnotatedMethods(final Class<?> clazz,
95              final Class<? extends Annotation> annotationClass) {
96          ClassEntry entry = new ClassEntry(clazz, annotationClass);
97          List<Method> result = methodCache.get(entry);
98          if (result != null) {
99              return result;
100         } else {
101             result = new ArrayList<Method>();
102             BeanDesc desc = BeanDescFactory.getBeanDesc(clazz);
103 
104             String[] methodNames = desc.getMethodNames();
105             for (int i = 0; i < methodNames.length; i++) {
106                 Method[] methods = desc.getMethods(methodNames[i]);
107 
108                 for (int j = 0; j < methods.length; j++) {
109                     if (methods[j].isAnnotationPresent(annotationClass)) {
110                         result.add(methods[j]);
111                     }
112                 }
113             }
114             methodCache.put(entry, result);
115 
116             return result;
117         }
118     }
119 
120     /**
121      * 特定のアノテーションが付加されたフィールドに対応する {@link PropertyDesc} を取得します。<br />
122      * <p>
123      * <code>class</code> で指定されたクラスから <code>annotationClass</code>
124      * で指定されたアノテーションが付加されたフィールドオブジェクトを検索し、それに対応する {@link PropertyDesc}
125      * オブジェクトのリストを返します。 フィールドは、親クラスまでさかのぼってすべて検索されます。
126      * </p>
127      * 
128      * @param clazz
129      *            対象クラス
130      * @param annotationClass
131      *            対象アノテーション
132      * @return 見つかった {@link PropertyDesc} のリスト
133      */
134     public static List<PropertyDesc> getAnnotatedPropertyDescs(
135             final Class<?> clazz,
136             final Class<? extends Annotation> annotationClass) {
137         ClassEntry entry = new ClassEntry(clazz, annotationClass);
138         List<PropertyDesc> result = pdCache.get(entry);
139         if (result != null) {
140             return result;
141         } else {
142             result = new ArrayList<PropertyDesc>();
143             BeanDesc desc = BeanDescFactory.getBeanDesc(clazz);
144             int fieldSize = desc.getFieldSize();
145             for (int i = 0; i < fieldSize; i++) {
146                 Field field = desc.getField(i);
147                 if (field.getAnnotation(annotationClass) != null) {
148                     String propertyName = field.getName();
149                     if (desc.hasPropertyDesc(propertyName)) {
150                         result.add(desc.getPropertyDesc(propertyName));
151                         pdCache.put(entry, result);
152                     }
153                 }
154             }
155             return result;
156         }
157     }
158 
159     private static class ClassEntry {
160         private Class<?> clazz;
161 
162         private Class<? extends Annotation> annotationClass;
163 
164         ClassEntry(final Class<?> clazz,
165                 final Class<? extends Annotation> annotationClass) {
166             this.clazz = clazz;
167             this.annotationClass = annotationClass;
168         }
169 
170         @Override
171         public int hashCode() {
172             final int PRIME = 31;
173             int result = 1;
174             result = PRIME
175                     * result
176                     + ((this.annotationClass == null) ? 0
177                             : this.annotationClass.hashCode());
178             result = PRIME * result
179                     + ((this.clazz == null) ? 0 : this.clazz.hashCode());
180             return result;
181         }
182 
183         @Override
184         public boolean equals(final Object obj) {
185             if (this == obj)
186                 return true;
187             if (obj == null)
188                 return false;
189             if (getClass() != obj.getClass())
190                 return false;
191             final ClassEntry other = (ClassEntry) obj;
192             if (this.annotationClass == null) {
193                 if (other.annotationClass != null)
194                     return false;
195             } else if (!this.annotationClass.equals(other.annotationClass))
196                 return false;
197             if (this.clazz == null) {
198                 if (other.clazz != null)
199                     return false;
200             } else if (!this.clazz.equals(other.clazz))
201                 return false;
202             return true;
203         }
204     }
205 }