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

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