001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.xbean.finder; 018 019import java.lang.annotation.Annotation; 020import java.lang.annotation.Documented; 021import java.lang.annotation.ElementType; 022import java.lang.annotation.Retention; 023import java.lang.annotation.Target; 024import java.lang.reflect.AnnotatedElement; 025import java.lang.reflect.Constructor; 026import java.lang.reflect.Method; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Map; 033 034import static java.util.Arrays.asList; 035 036/** 037* @version $Rev$ $Date$ 038*/ 039public class MetaAnnotatedElement<T extends AnnotatedElement> implements AnnotatedElement, MetaAnnotated<T> { 040 protected final Map<Class<? extends Annotation>, MetaAnnotation<?>> annotations = new HashMap<Class<? extends Annotation>, MetaAnnotation<?>>(); 041 protected final T target; 042 043 public MetaAnnotatedElement(T element) { 044 this(element, unroll(element)); 045 } 046 047 MetaAnnotatedElement(T target, Map<Class<? extends Annotation>, MetaAnnotation<?>> annotations) { 048 this.target = target; 049 this.annotations.putAll(annotations); 050 } 051 052 public T get() { 053 return target; 054 } 055 056 public Annotation[] getDeclaredAnnotations() { 057 return target.getDeclaredAnnotations(); 058 } 059 060 public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { 061 return annotations.containsKey(annotationClass); 062 } 063 064 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 065 MetaAnnotation<T> annotation = (MetaAnnotation<T>) annotations.get(annotationClass); 066 return (annotation == null) ? null : annotation.get(); 067 } 068 069 public Annotation[] getAnnotations() { 070 Annotation[] annotations = new Annotation[this.annotations.size()]; 071 072 int i = 0; 073 for (MetaAnnotation annotation : this.annotations.values()) { 074 annotations[i++] = annotation.get(); 075 } 076 077 return annotations; 078 } 079 080 public Collection<MetaAnnotation<?>> getMetaAnnotations() { 081 return Collections.unmodifiableCollection(annotations.values()); 082 } 083 084 @Override 085 public boolean equals(Object obj) { 086 return get().equals(obj); 087 } 088 089 @Override 090 public int hashCode() { 091 return get().hashCode(); 092 } 093 094 @Override 095 public String toString() { 096 return get().toString(); 097 } 098 099 100 private static void unroll(Class<? extends Annotation> clazz, int depth, Map<Class<? extends Annotation>, MetaAnnotation<?>> found) { 101 if (!isMetaAnnotation(clazz)) return; 102 103 for (Annotation annotation : getDeclaredMetaAnnotations(clazz)) { 104 Class<? extends Annotation> type = annotation.annotationType(); 105 106 MetaAnnotation existing = found.get(type); 107 108 if (existing != null) { 109 110 if (existing.getDepth() > depth) { 111 112 // OVERWRITE 113 114 found.put(type, new MetaAnnotation(annotation, depth)); 115 116 unroll(type, depth + 1, found); 117 118 } else if (existing.getDepth() < depth) { 119 120 // IGNORE 121 122 // ignore, what we have already is higher priority 123 124 } else { 125 126 // CONFLICT 127 128 // They are the same depth and therefore conflicting 129 existing.getConflicts().add(new MetaAnnotation(annotation, depth)); 130 131 } 132 133 } else { 134 135 // NEW 136 137 found.put(type, new MetaAnnotation(annotation, depth)); 138 139 unroll(type, depth + 1, found); 140 141 } 142 } 143 } 144 145 private static Collection<Annotation> getDeclaredMetaAnnotations(Class<? extends Annotation> clazz) { 146 147 Map<Class, Annotation> map = new HashMap<Class, Annotation>(); 148 149 // pull in the annotations declared on this annotation 150 151 for (Annotation annotation : clazz.getDeclaredAnnotations()) { 152 map.put(annotation.annotationType(), annotation); 153 } 154 155 List<Annotation[]> groups = new ArrayList<Annotation[]>(); 156 157 Class<? extends Annotation> metatype = getMetatype(clazz); 158 if (metatype != null) { 159 try { 160 Class<?> def = clazz.getClassLoader().loadClass(clazz.getName() + "$$"); 161 162 List<AnnotatedElement> elements = new ArrayList<AnnotatedElement>(); 163 164 elements.addAll(asList(def.getDeclaredFields())); 165 elements.addAll(asList(def.getDeclaredConstructors())); 166 elements.addAll(asList(def.getDeclaredMethods())); 167 168 for (Method method : def.getDeclaredMethods()) { 169 for (Annotation[] array : method.getParameterAnnotations()) { 170 groups.add(array); 171 } 172 } 173 174 for (Constructor constructor : def.getDeclaredConstructors()) { 175 for (Annotation[] array : constructor.getParameterAnnotations()) { 176 groups.add(array); 177 } 178 } 179 180 for (AnnotatedElement element : elements) { 181 groups.add(element.getDeclaredAnnotations()); 182 } 183 184 for (Annotation[] annotations : groups) { 185 if (contains(annotations, clazz)) { 186 for (Annotation annotation : annotations) { 187 map.put(annotation.annotationType(), annotation); 188 } 189 } 190 } 191 } catch (ClassNotFoundException e) { 192 // inner class is optional 193 } 194 } 195 196 map.remove(Target.class); 197 map.remove(Retention.class); 198 map.remove(Documented.class); 199 map.remove(metatype); 200 map.remove(clazz); 201 202 return map.values(); 203 } 204 205 private static boolean contains(Annotation[] annotations, Class<? extends Annotation> clazz) { 206 for (Annotation annotation : annotations) { 207 if (clazz.equals(annotation.annotationType())) return true; 208 } 209 return false; 210 } 211 212 private static Class<? extends Annotation> getMetatype(Class<? extends Annotation> clazz) { 213 for (Annotation annotation : clazz.getDeclaredAnnotations()) { 214 Class<? extends Annotation> type = annotation.annotationType(); 215 216 if (isMetatypeAnnotation(type)) return type; 217 } 218 219 return null; 220 } 221 222 private static boolean isMetaAnnotation(Class<? extends Annotation> clazz) { 223 for (Annotation annotation : clazz.getDeclaredAnnotations()) { 224 if (isMetatypeAnnotation(annotation.annotationType())) return true; 225 } 226 227 return false; 228 } 229 230 private static boolean isMetatypeAnnotation(Class<? extends Annotation> type) { 231 if (type.getName().equals("javax.annotation.Metatype")) return true; 232 if (isSelfAnnotated(type, "Metatype")) return true; 233 234 for (Annotation annotation : type.getAnnotations()) { 235 if (type.getName().equals("javax.annotation.Metaroot")) return true; 236 if (isSelfAnnotated(annotation.annotationType(), "Metaroot")) return true; 237 } 238 239 return false; 240 } 241 242 private static boolean isSelfAnnotated(Class<? extends Annotation> type, String name) { 243 return type.isAnnotationPresent(type) && type.getSimpleName().equals(name) && validTarget(type); 244 } 245 246 private static boolean validTarget(Class<? extends Annotation> type) { 247 final Target target = type.getAnnotation(Target.class); 248 249 if (target == null) return false; 250 251 final ElementType[] targets = target.value(); 252 253 return targets.length == 1 && targets[0] == ElementType.ANNOTATION_TYPE; 254 } 255 256 protected static Map<Class<? extends Annotation>, MetaAnnotation<?>> unroll(AnnotatedElement element) { 257 return unroll(element.getDeclaredAnnotations()); 258 } 259 260 protected static Map<Class<? extends Annotation>, MetaAnnotation<?>> unroll(Annotation[] annotations) { 261 final Map<Class<? extends Annotation>, MetaAnnotation<?>> map = new HashMap<Class<? extends Annotation>, MetaAnnotation<?>>(); 262 263 for (Annotation annotation : annotations) { 264 265 map.put(annotation.annotationType(), new MetaAnnotation(annotation, 0)); 266 267 unroll(annotation.annotationType(), 1, map); 268 269 } 270 271 return map; 272 } 273 274 protected Annotation[][] unrollParameters(Annotation[][] parameterAnnotations) { 275 final Annotation[][] unrolledParameters = new Annotation[parameterAnnotations.length][]; 276 277 int i = 0; 278 for (Annotation[] annotations : parameterAnnotations) { 279 final Map<Class<? extends Annotation>, MetaAnnotation<?>> map = unroll(annotations); 280 281 int j = 0; 282 283 final Annotation[] unrolled = new Annotation[map.size()]; 284 for (MetaAnnotation<?> metaAnnotation : map.values()) { 285 unrolled[j++] = metaAnnotation.get(); 286 } 287 288 unrolledParameters[i++] = unrolled; 289 } 290 return unrolledParameters; 291 } 292}