Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

Java15AnnotationFinder.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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.classfile.annotation.AnnotationGen;
  28. import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository;
  29. import org.aspectj.apache.bcel.util.Repository;
  30. import org.aspectj.weaver.AnnotationAJ;
  31. import org.aspectj.weaver.ResolvedType;
  32. import org.aspectj.weaver.UnresolvedType;
  33. import org.aspectj.weaver.World;
  34. import org.aspectj.weaver.bcel.BcelAnnotation;
  35. import org.aspectj.weaver.bcel.BcelWeakClassLoaderReference;
  36. /**
  37. * Find the given annotation (if present) on the given object
  38. *
  39. */
  40. public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
  41. private Repository bcelRepository;
  42. private BcelWeakClassLoaderReference classLoaderRef;
  43. private World world;
  44. // must have no-arg constructor for reflective construction
  45. public Java15AnnotationFinder() {
  46. }
  47. public void setClassLoader(ClassLoader aLoader) {
  48. // TODO: No easy way to ask the world factory for the right kind of
  49. // repository so
  50. // default to the safe one! (pr160674)
  51. this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
  52. this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
  53. }
  54. public void setWorld(World aWorld) {
  55. this.world = aWorld;
  56. }
  57. /*
  58. * (non-Javadoc)
  59. *
  60. * @see org.aspectj.weaver.reflect.AnnotationFinder#getAnnotation(org.aspectj .weaver.ResolvedType, java.lang.Object)
  61. */
  62. public Object getAnnotation(ResolvedType annotationType, Object onObject) {
  63. try {
  64. Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
  65. false, getClassLoader());
  66. if (onObject.getClass().isAnnotationPresent(annotationClass)) {
  67. return onObject.getClass().getAnnotation(annotationClass);
  68. }
  69. } catch (ClassNotFoundException ex) {
  70. // just return null
  71. }
  72. return null;
  73. }
  74. public Object getAnnotationFromClass(ResolvedType annotationType, Class aClass) {
  75. try {
  76. Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
  77. false, getClassLoader());
  78. if (aClass.isAnnotationPresent(annotationClass)) {
  79. return aClass.getAnnotation(annotationClass);
  80. }
  81. } catch (ClassNotFoundException ex) {
  82. // just return null
  83. }
  84. return null;
  85. }
  86. public Object getAnnotationFromMember(ResolvedType annotationType, Member aMember) {
  87. if (!(aMember instanceof AccessibleObject))
  88. return null;
  89. AccessibleObject ao = (AccessibleObject) aMember;
  90. try {
  91. Class annotationClass = Class.forName(annotationType.getName(), false, getClassLoader());
  92. if (ao.isAnnotationPresent(annotationClass)) {
  93. return ao.getAnnotation(annotationClass);
  94. }
  95. } catch (ClassNotFoundException ex) {
  96. // just return null
  97. }
  98. return null;
  99. }
  100. private ClassLoader getClassLoader() {
  101. return classLoaderRef.getClassLoader();
  102. }
  103. public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) {
  104. if (!(onMember instanceof AccessibleObject))
  105. return null;
  106. // here we really want both the runtime visible AND the class visible
  107. // annotations
  108. // so we bail out to Bcel and then chuck away the JavaClass so that we
  109. // don't hog
  110. // memory.
  111. try {
  112. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  113. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  114. if (onMember instanceof Method) {
  115. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  116. if (bcelMethod == null) {
  117. // pr220430
  118. // System.err.println(
  119. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  120. // +
  121. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  122. } else {
  123. anns = bcelMethod.getAnnotations();
  124. }
  125. } else if (onMember instanceof Constructor) {
  126. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
  127. anns = bcelCons.getAnnotations();
  128. } else if (onMember instanceof Field) {
  129. org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
  130. anns = bcelField.getAnnotations();
  131. }
  132. // the answer is cached and we don't want to hold on to memory
  133. bcelRepository.clear();
  134. // OPTIMIZE make constant 0 size array for sharing
  135. if (anns == null)
  136. anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  137. // convert to our Annotation type
  138. for (int i = 0; i < anns.length; i++) {
  139. if (anns[i].getTypeSignature().equals(ofType.getSignature())) {
  140. return new BcelAnnotation(anns[i], world);
  141. }
  142. }
  143. return null;
  144. } catch (ClassNotFoundException cnfEx) {
  145. // just use reflection then
  146. }
  147. return null;
  148. }
  149. public String getAnnotationDefaultValue(Member onMember) {
  150. try {
  151. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  152. if (onMember instanceof Method) {
  153. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  154. if (bcelMethod == null) {
  155. // pr220430
  156. // System.err.println(
  157. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  158. // +
  159. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  160. } else {
  161. Attribute[] attrs = bcelMethod.getAttributes();
  162. for (int i = 0; i < attrs.length; i++) {
  163. Attribute attribute = attrs[i];
  164. if (attribute.getName().equals("AnnotationDefault")) {
  165. AnnotationDefault def = (AnnotationDefault) attribute;
  166. return def.getElementValue().stringifyValue();
  167. }
  168. }
  169. return null;
  170. }
  171. }
  172. } catch (ClassNotFoundException cnfEx) {
  173. // just use reflection then
  174. }
  175. return null;
  176. }
  177. public Set getAnnotations(Member onMember) {
  178. if (!(onMember instanceof AccessibleObject))
  179. return Collections.EMPTY_SET;
  180. // here we really want both the runtime visible AND the class visible
  181. // annotations
  182. // so we bail out to Bcel and then chuck away the JavaClass so that we
  183. // don't hog
  184. // memory.
  185. try {
  186. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  187. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  188. if (onMember instanceof Method) {
  189. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  190. if (bcelMethod == null) {
  191. // fallback on reflection - see pr220430
  192. // System.err.println(
  193. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  194. // +
  195. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  196. } else {
  197. anns = bcelMethod.getAnnotations();
  198. }
  199. } else if (onMember instanceof Constructor) {
  200. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
  201. anns = bcelCons.getAnnotations();
  202. } else if (onMember instanceof Field) {
  203. org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
  204. anns = bcelField.getAnnotations();
  205. }
  206. // the answer is cached and we don't want to hold on to memory
  207. bcelRepository.clear();
  208. // OPTIMIZE make this a constant 0 size array
  209. if (anns == null)
  210. anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
  211. // convert to our Annotation type
  212. Set<ResolvedType> annSet = new HashSet<ResolvedType>();
  213. for (int i = 0; i < anns.length; i++) {
  214. annSet.add(world.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature())));
  215. }
  216. return annSet;
  217. } catch (ClassNotFoundException cnfEx) {
  218. // just use reflection then
  219. }
  220. AccessibleObject ao = (AccessibleObject) onMember;
  221. Annotation[] anns = ao.getDeclaredAnnotations();
  222. Set<UnresolvedType> annSet = new HashSet<UnresolvedType>();
  223. for (int i = 0; i < anns.length; i++) {
  224. annSet.add(UnresolvedType.forName(anns[i].annotationType().getName()).resolve(world));
  225. }
  226. return annSet;
  227. }
  228. public ResolvedType[] getAnnotations(Class forClass, World inWorld) {
  229. // here we really want both the runtime visible AND the class visible
  230. // annotations
  231. // so we bail out to Bcel and then chuck away the JavaClass so that we
  232. // don't hog
  233. // memory.
  234. try {
  235. JavaClass jc = bcelRepository.loadClass(forClass);
  236. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations();
  237. bcelRepository.clear();
  238. if (anns == null)
  239. return ResolvedType.NONE;
  240. ResolvedType[] ret = new ResolvedType[anns.length];
  241. for (int i = 0; i < ret.length; i++) {
  242. ret[i] = inWorld.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()));
  243. }
  244. return ret;
  245. } catch (ClassNotFoundException cnfEx) {
  246. // just use reflection then
  247. }
  248. Annotation[] classAnnotations = forClass.getAnnotations();
  249. ResolvedType[] ret = new ResolvedType[classAnnotations.length];
  250. for (int i = 0; i < classAnnotations.length; i++) {
  251. ret[i] = inWorld.resolve(classAnnotations[i].annotationType().getName());
  252. }
  253. return ret;
  254. }
  255. public String[] getParameterNames(Member forMember) {
  256. if (!(forMember instanceof AccessibleObject))
  257. return null;
  258. try {
  259. JavaClass jc = bcelRepository.loadClass(forMember.getDeclaringClass());
  260. LocalVariableTable lvt = null;
  261. int numVars = 0;
  262. if (forMember instanceof Method) {
  263. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) forMember);
  264. lvt = bcelMethod.getLocalVariableTable();
  265. numVars = bcelMethod.getArgumentTypes().length;
  266. } else if (forMember instanceof Constructor) {
  267. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) forMember);
  268. lvt = bcelCons.getLocalVariableTable();
  269. numVars = bcelCons.getArgumentTypes().length;
  270. }
  271. return getParameterNamesFromLVT(lvt, numVars);
  272. } catch (ClassNotFoundException cnfEx) {
  273. ; // no luck
  274. }
  275. return null;
  276. }
  277. private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) {
  278. if (lvt == null)
  279. return null;// pr222987 - prevent NPE
  280. LocalVariable[] vars = lvt.getLocalVariableTable();
  281. if (vars.length < numVars) {
  282. // basic error, we can't get the names...
  283. return null;
  284. }
  285. String[] ret = new String[numVars];
  286. for (int i = 0; i < numVars; i++) {
  287. ret[i] = vars[i + 1].getName();
  288. }
  289. return ret;
  290. }
  291. public static final ResolvedType[][] NO_PARAMETER_ANNOTATIONS = new ResolvedType[][] {};
  292. public ResolvedType[][] getParameterAnnotationTypes(Member onMember) {
  293. if (!(onMember instanceof AccessibleObject))
  294. return NO_PARAMETER_ANNOTATIONS;
  295. // here we really want both the runtime visible AND the class visible
  296. // annotations
  297. // so we bail out to Bcel and then chuck away the JavaClass so that we
  298. // don't hog 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. public Object getParamAnnotation(Member onMember, int argsIndex, int paramAnnoIndex) {
  362. if (!(onMember instanceof AccessibleObject))
  363. return null;
  364. // here we really want both the runtime visible AND the class visible
  365. // annotations so we bail out to Bcel and then chuck away the JavaClass so that we
  366. // don't hog memory.
  367. // try {
  368. // JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  369. // org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
  370. // if (onMember instanceof Method) {
  371. // org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  372. // if (bcelMethod == null) {
  373. // // pr220430
  374. // // System.err.println(
  375. // // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  376. // // + onMember.getName()+"' in class '"+jc.getClassName()+"'");
  377. // } else {
  378. // anns = bcelMethod.getParameterAnnotations();
  379. // }
  380. // } else if (onMember instanceof Constructor) {
  381. // org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
  382. // anns = bcelCons.getParameterAnnotations();
  383. // } else if (onMember instanceof Field) {
  384. // // anns = null;
  385. // }
  386. // // the answer is cached and we don't want to hold on to memory
  387. // bcelRepository.clear();
  388. // if (anns == null)
  389. // return null;
  390. //
  391. // if (argsIndex>=anns.length) {
  392. // return null;
  393. // }
  394. // AnnotationGen[] parameterAnnotationsOnParticularArg = anns[argsIndex];
  395. // if (parameterAnnotationsOnParticularArg==null || paramAnnoIndex>=parameterAnnotationsOnParticularArg.length) {
  396. // return null;
  397. // }
  398. // AnnotationGen parameterAnnotation = parameterAnnotationsOnParticularArg[paramAnnoIndex];
  399. //// if (parameterAnnotation.getTypeSignature().equals(ofType.getSignature())) {
  400. // return new BcelAnnotation(parameterAnnotation, world);
  401. //// } else {
  402. //// return null;
  403. //// }
  404. // } catch (ClassNotFoundException cnfEx) {
  405. // // just use reflection then
  406. // }
  407. // reflection...
  408. AccessibleObject ao = (AccessibleObject) onMember;
  409. Annotation[][] anns = null;
  410. if (onMember instanceof Method) {
  411. anns = ((Method) ao).getParameterAnnotations();
  412. } else if (onMember instanceof Constructor) {
  413. anns = ((Constructor) ao).getParameterAnnotations();
  414. } else if (onMember instanceof Field) {
  415. // anns = null;
  416. }
  417. if (anns == null || argsIndex>=anns.length) {
  418. return null;
  419. }
  420. Annotation[] parameterAnnotationsOnParticularArg = anns[argsIndex];
  421. if (parameterAnnotationsOnParticularArg==null || paramAnnoIndex>=parameterAnnotationsOnParticularArg.length) {
  422. return null;
  423. }
  424. return parameterAnnotationsOnParticularArg[paramAnnoIndex];
  425. }
  426. }