You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Java15AnnotationFinder.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* *******************************************************************
  2. * Copyright (c) 2005 Contributors.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Adrian Colyer Initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.reflect;
  13. import java.lang.annotation.Annotation;
  14. import java.lang.reflect.AccessibleObject;
  15. import java.lang.reflect.Constructor;
  16. import java.lang.reflect.Field;
  17. import java.lang.reflect.Member;
  18. import java.lang.reflect.Method;
  19. import java.util.Collections;
  20. import java.util.HashSet;
  21. import java.util.Set;
  22. import org.aspectj.apache.bcel.classfile.AnnotationDefault;
  23. import org.aspectj.apache.bcel.classfile.Attribute;
  24. import org.aspectj.apache.bcel.classfile.JavaClass;
  25. import org.aspectj.apache.bcel.classfile.LocalVariable;
  26. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  27. import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository;
  28. import org.aspectj.apache.bcel.util.Repository;
  29. import org.aspectj.weaver.AnnotationAJ;
  30. import org.aspectj.weaver.ResolvedType;
  31. import org.aspectj.weaver.UnresolvedType;
  32. import org.aspectj.weaver.World;
  33. import org.aspectj.weaver.bcel.BcelAnnotation;
  34. import org.aspectj.weaver.bcel.BcelWeakClassLoaderReference;
  35. /**
  36. * Find the given annotation (if present) on the given object
  37. *
  38. */
  39. public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
  40. private Repository bcelRepository;
  41. private BcelWeakClassLoaderReference classLoaderRef;
  42. private World world;
  43. // must have no-arg constructor for reflective construction
  44. public Java15AnnotationFinder() {
  45. }
  46. public void setClassLoader(ClassLoader aLoader) {
  47. // TODO: No easy way to ask the world factory for the right kind of
  48. // repository so
  49. // default to the safe one! (pr160674)
  50. this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
  51. this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
  52. }
  53. public void setWorld(World aWorld) {
  54. this.world = aWorld;
  55. }
  56. /*
  57. * (non-Javadoc)
  58. *
  59. * @see org.aspectj.weaver.reflect.AnnotationFinder#getAnnotation(org.aspectj .weaver.ResolvedType, java.lang.Object)
  60. */
  61. public Object getAnnotation(ResolvedType annotationType, Object onObject) {
  62. try {
  63. Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
  64. false, getClassLoader());
  65. if (onObject.getClass().isAnnotationPresent(annotationClass)) {
  66. return onObject.getClass().getAnnotation(annotationClass);
  67. }
  68. } catch (ClassNotFoundException ex) {
  69. // just return null
  70. }
  71. return null;
  72. }
  73. public Object getAnnotationFromClass(ResolvedType annotationType, Class aClass) {
  74. try {
  75. Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
  76. false, getClassLoader());
  77. if (aClass.isAnnotationPresent(annotationClass)) {
  78. return aClass.getAnnotation(annotationClass);
  79. }
  80. } catch (ClassNotFoundException ex) {
  81. // just return null
  82. }
  83. return null;
  84. }
  85. public Object getAnnotationFromMember(ResolvedType annotationType, Member aMember) {
  86. if (!(aMember instanceof AccessibleObject))
  87. return null;
  88. AccessibleObject ao = (AccessibleObject) aMember;
  89. try {
  90. Class annotationClass = Class.forName(annotationType.getName(), false, getClassLoader());
  91. if (ao.isAnnotationPresent(annotationClass)) {
  92. return ao.getAnnotation(annotationClass);
  93. }
  94. } catch (ClassNotFoundException ex) {
  95. // just return null
  96. }
  97. return null;
  98. }
  99. private ClassLoader getClassLoader() {
  100. return classLoaderRef.getClassLoader();
  101. }
  102. public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) {
  103. if (!(onMember instanceof AccessibleObject))
  104. return null;
  105. // here we really want both the runtime visible AND the class visible
  106. // annotations
  107. // so we bail out to Bcel and then chuck away the JavaClass so that we
  108. // don't hog
  109. // memory.
  110. try {
  111. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  112. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  113. if (onMember instanceof Method) {
  114. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  115. if (bcelMethod == null) {
  116. // pr220430
  117. // System.err.println(
  118. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  119. // +
  120. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  121. } else {
  122. anns = bcelMethod.getAnnotations();
  123. }
  124. } else if (onMember instanceof Constructor) {
  125. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
  126. anns = bcelCons.getAnnotations();
  127. } else if (onMember instanceof Field) {
  128. org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
  129. anns = bcelField.getAnnotations();
  130. }
  131. // the answer is cached and we don't want to hold on to memory
  132. bcelRepository.clear();
  133. // OPTIMIZE make constant 0 size array for sharing
  134. if (anns == null)
  135. anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  136. // convert to our Annotation type
  137. for (int i = 0; i < anns.length; i++) {
  138. if (anns[i].getTypeSignature().equals(ofType.getSignature())) {
  139. return new BcelAnnotation(anns[i], world);
  140. }
  141. }
  142. return null;
  143. } catch (ClassNotFoundException cnfEx) {
  144. // just use reflection then
  145. }
  146. return null;
  147. }
  148. public String getAnnotationDefaultValue(Member onMember) {
  149. try {
  150. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  151. if (onMember instanceof Method) {
  152. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  153. if (bcelMethod == null) {
  154. // pr220430
  155. // System.err.println(
  156. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  157. // +
  158. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  159. } else {
  160. Attribute[] attrs = bcelMethod.getAttributes();
  161. for (int i = 0; i < attrs.length; i++) {
  162. Attribute attribute = attrs[i];
  163. if (attribute.getName().equals("AnnotationDefault")) {
  164. AnnotationDefault def = (AnnotationDefault) attribute;
  165. return def.getElementValue().stringifyValue();
  166. }
  167. }
  168. return null;
  169. }
  170. }
  171. } catch (ClassNotFoundException cnfEx) {
  172. // just use reflection then
  173. }
  174. return null;
  175. }
  176. public Set getAnnotations(Member onMember) {
  177. if (!(onMember instanceof AccessibleObject))
  178. return Collections.EMPTY_SET;
  179. // here we really want both the runtime visible AND the class visible
  180. // annotations
  181. // so we bail out to Bcel and then chuck away the JavaClass so that we
  182. // don't hog
  183. // memory.
  184. try {
  185. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  186. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  187. if (onMember instanceof Method) {
  188. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  189. if (bcelMethod == null) {
  190. // fallback on reflection - see pr220430
  191. // System.err.println(
  192. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  193. // +
  194. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  195. } else {
  196. anns = bcelMethod.getAnnotations();
  197. }
  198. } else if (onMember instanceof Constructor) {
  199. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
  200. anns = bcelCons.getAnnotations();
  201. } else if (onMember instanceof Field) {
  202. org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
  203. anns = bcelField.getAnnotations();
  204. }
  205. // the answer is cached and we don't want to hold on to memory
  206. bcelRepository.clear();
  207. // OPTIMIZE make this a constant 0 size array
  208. if (anns == null)
  209. anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  210. // convert to our Annotation type
  211. Set<ResolvedType> annSet = new HashSet<ResolvedType>();
  212. for (int i = 0; i < anns.length; i++) {
  213. annSet.add(world.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature())));
  214. }
  215. return annSet;
  216. } catch (ClassNotFoundException cnfEx) {
  217. // just use reflection then
  218. }
  219. AccessibleObject ao = (AccessibleObject) onMember;
  220. Annotation[] anns = ao.getDeclaredAnnotations();
  221. Set<UnresolvedType> annSet = new HashSet<UnresolvedType>();
  222. for (int i = 0; i < anns.length; i++) {
  223. annSet.add(UnresolvedType.forName(anns[i].annotationType().getName()).resolve(world));
  224. }
  225. return annSet;
  226. }
  227. public ResolvedType[] getAnnotations(Class forClass, World inWorld) {
  228. // here we really want both the runtime visible AND the class visible
  229. // annotations
  230. // so we bail out to Bcel and then chuck away the JavaClass so that we
  231. // don't hog
  232. // memory.
  233. try {
  234. JavaClass jc = bcelRepository.loadClass(forClass);
  235. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations();
  236. bcelRepository.clear();
  237. if (anns == null)
  238. return ResolvedType.NONE;
  239. ResolvedType[] ret = new ResolvedType[anns.length];
  240. for (int i = 0; i < ret.length; i++) {
  241. ret[i] = inWorld.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()));
  242. }
  243. return ret;
  244. } catch (ClassNotFoundException cnfEx) {
  245. // just use reflection then
  246. }
  247. Annotation[] classAnnotations = forClass.getAnnotations();
  248. ResolvedType[] ret = new ResolvedType[classAnnotations.length];
  249. for (int i = 0; i < classAnnotations.length; i++) {
  250. ret[i] = inWorld.resolve(classAnnotations[i].annotationType().getName());
  251. }
  252. return ret;
  253. }
  254. public String[] getParameterNames(Member forMember) {
  255. if (!(forMember instanceof AccessibleObject))
  256. return null;
  257. try {
  258. JavaClass jc = bcelRepository.loadClass(forMember.getDeclaringClass());
  259. LocalVariableTable lvt = null;
  260. int numVars = 0;
  261. if (forMember instanceof Method) {
  262. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) forMember);
  263. lvt = bcelMethod.getLocalVariableTable();
  264. numVars = bcelMethod.getArgumentTypes().length;
  265. } else if (forMember instanceof Constructor) {
  266. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) forMember);
  267. lvt = bcelCons.getLocalVariableTable();
  268. numVars = bcelCons.getArgumentTypes().length;
  269. }
  270. return getParameterNamesFromLVT(lvt, numVars);
  271. } catch (ClassNotFoundException cnfEx) {
  272. ; // no luck
  273. }
  274. return null;
  275. }
  276. private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) {
  277. if (lvt == null)
  278. return null;// pr222987 - prevent NPE
  279. LocalVariable[] vars = lvt.getLocalVariableTable();
  280. if (vars.length < numVars) {
  281. // basic error, we can't get the names...
  282. return null;
  283. }
  284. String[] ret = new String[numVars];
  285. for (int i = 0; i < numVars; i++) {
  286. ret[i] = vars[i + 1].getName();
  287. }
  288. return ret;
  289. }
  290. public static final ResolvedType[][] NO_PARAMETER_ANNOTATIONS = new ResolvedType[][] {};
  291. public ResolvedType[][] getParameterAnnotationTypes(Member onMember) {
  292. if (!(onMember instanceof AccessibleObject))
  293. return NO_PARAMETER_ANNOTATIONS;
  294. // here we really want both the runtime visible AND the class visible
  295. // annotations
  296. // so we bail out to Bcel and then chuck away the JavaClass so that we
  297. // don't hog
  298. // memory.
  299. try {
  300. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  301. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
  302. if (onMember instanceof Method) {
  303. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  304. if (bcelMethod == null) {
  305. // pr220430
  306. // System.err.println(
  307. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  308. // +
  309. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  310. } else {
  311. anns = bcelMethod.getParameterAnnotations();
  312. }
  313. } else if (onMember instanceof Constructor) {
  314. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
  315. anns = bcelCons.getParameterAnnotations();
  316. } else if (onMember instanceof Field) {
  317. // anns = null;
  318. }
  319. // the answer is cached and we don't want to hold on to memory
  320. bcelRepository.clear();
  321. if (anns == null)
  322. return NO_PARAMETER_ANNOTATIONS;
  323. ResolvedType[][] result = new ResolvedType[anns.length][];
  324. // CACHING??
  325. for (int i = 0; i < anns.length; i++) {
  326. if (anns[i] != null) {
  327. result[i] = new ResolvedType[anns[i].length];
  328. for (int j = 0; j < anns[i].length; j++) {
  329. result[i][j] = world.resolve(UnresolvedType.forSignature(anns[i][j].getTypeSignature()));
  330. }
  331. }
  332. }
  333. return result;
  334. } catch (ClassNotFoundException cnfEx) {
  335. // just use reflection then
  336. }
  337. // reflection...
  338. AccessibleObject ao = (AccessibleObject) onMember;
  339. Annotation[][] anns = null;
  340. if (onMember instanceof Method) {
  341. anns = ((Method) ao).getParameterAnnotations();
  342. } else if (onMember instanceof Constructor) {
  343. anns = ((Constructor) ao).getParameterAnnotations();
  344. } else if (onMember instanceof Field) {
  345. // anns = null;
  346. }
  347. if (anns == null)
  348. return NO_PARAMETER_ANNOTATIONS;
  349. ResolvedType[][] result = new ResolvedType[anns.length][];
  350. // CACHING??
  351. for (int i = 0; i < anns.length; i++) {
  352. if (anns[i] != null) {
  353. result[i] = new ResolvedType[anns[i].length];
  354. for (int j = 0; j < anns[i].length; j++) {
  355. result[i][j] = UnresolvedType.forName(anns[i][j].annotationType().getName()).resolve(world);
  356. }
  357. }
  358. }
  359. return result;
  360. }
  361. }