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 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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 static Repository staticBcelRepository;
  41. private static BcelWeakClassLoaderReference staticClassLoaderRef;
  42. private World world;
  43. private static boolean useCachingClassLoaderRepository;
  44. // Use single instance of Repository and ClassLoader
  45. public static boolean useSingleInstances =
  46. System.getProperty("org.aspectj.apache.bcel.useSingleRepositoryInstance", "false").equalsIgnoreCase("true");
  47. static {
  48. try {
  49. useCachingClassLoaderRepository = System.getProperty("Xset:bcelRepositoryCaching","true").equalsIgnoreCase("true");
  50. } catch (Throwable t) {
  51. useCachingClassLoaderRepository = false;
  52. }
  53. }
  54. // must have no-arg constructor for reflective construction
  55. public Java15AnnotationFinder() {
  56. }
  57. public void setClassLoader(ClassLoader aLoader) {
  58. // Set class loader ref
  59. if (useSingleInstances && staticClassLoaderRef == null) {
  60. staticClassLoaderRef = new BcelWeakClassLoaderReference(aLoader);
  61. } else {
  62. this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
  63. }
  64. // Set repository
  65. if (useCachingClassLoaderRepository) {
  66. if (useSingleInstances && staticBcelRepository == null) {
  67. staticBcelRepository = new ClassLoaderRepository(getClassLoader());
  68. } else {
  69. this.bcelRepository = new ClassLoaderRepository(classLoaderRef);
  70. }
  71. } else {
  72. if (useSingleInstances && staticBcelRepository == null) {
  73. staticBcelRepository = new NonCachingClassLoaderRepository(getClassLoader());
  74. } else {
  75. this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
  76. }
  77. }
  78. }
  79. private Repository getBcelRepository() {
  80. return useSingleInstances ? staticBcelRepository : bcelRepository;
  81. }
  82. public void setWorld(World aWorld) {
  83. this.world = aWorld;
  84. }
  85. public Object getAnnotation(ResolvedType annotationType, Object onObject) {
  86. try {
  87. Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
  88. false, getClassLoader());
  89. if (onObject.getClass().isAnnotationPresent(annotationClass)) {
  90. return onObject.getClass().getAnnotation(annotationClass);
  91. }
  92. } catch (ClassNotFoundException ex) {
  93. // just return null
  94. }
  95. return null;
  96. }
  97. public Object getAnnotationFromClass(ResolvedType annotationType, Class aClass) {
  98. try {
  99. Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
  100. false, getClassLoader());
  101. if (aClass.isAnnotationPresent(annotationClass)) {
  102. return aClass.getAnnotation(annotationClass);
  103. }
  104. } catch (ClassNotFoundException ex) {
  105. // just return null
  106. }
  107. return null;
  108. }
  109. public Object getAnnotationFromMember(ResolvedType annotationType, Member aMember) {
  110. if (!(aMember instanceof AccessibleObject))
  111. return null;
  112. AccessibleObject ao = (AccessibleObject) aMember;
  113. try {
  114. Class annotationClass = Class.forName(annotationType.getName(), false, getClassLoader());
  115. if (ao.isAnnotationPresent(annotationClass)) {
  116. return ao.getAnnotation(annotationClass);
  117. }
  118. } catch (ClassNotFoundException ex) {
  119. // just return null
  120. }
  121. return null;
  122. }
  123. private ClassLoader getClassLoader() {
  124. return useSingleInstances ? staticClassLoaderRef.getClassLoader() : classLoaderRef.getClassLoader();
  125. }
  126. public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) {
  127. if (!(onMember instanceof AccessibleObject))
  128. return null;
  129. // here we really want both the runtime visible AND the class visible
  130. // annotations
  131. // so we bail out to Bcel and then chuck away the JavaClass so that we
  132. // don't hog
  133. // memory.
  134. try {
  135. JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
  136. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = AnnotationGen.NO_ANNOTATIONS;
  137. if (onMember instanceof Method) {
  138. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  139. if (bcelMethod == null) {
  140. // pr220430
  141. // System.err.println(
  142. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  143. // +
  144. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  145. } else {
  146. anns = bcelMethod.getAnnotations();
  147. }
  148. } else if (onMember instanceof Constructor) {
  149. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor<?>) onMember);
  150. anns = bcelCons.getAnnotations();
  151. } else if (onMember instanceof Field) {
  152. org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
  153. anns = bcelField.getAnnotations();
  154. }
  155. // the answer is cached and we don't want to hold on to memory
  156. getBcelRepository().clear();
  157. // OPTIMIZE make constant 0 size array for sharing
  158. if (anns == null)
  159. anns = AnnotationGen.NO_ANNOTATIONS;
  160. // convert to our Annotation type
  161. for (org.aspectj.apache.bcel.classfile.annotation.AnnotationGen ann : anns) {
  162. if (ann.getTypeSignature().equals(ofType.getSignature())) {
  163. return new BcelAnnotation(ann, world);
  164. }
  165. }
  166. return null;
  167. } catch (ClassNotFoundException cnfEx) {
  168. // just use reflection then
  169. }
  170. return null;
  171. }
  172. public String getAnnotationDefaultValue(Member onMember) {
  173. try {
  174. JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
  175. if (onMember instanceof Method) {
  176. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  177. if (bcelMethod == null) {
  178. // pr220430
  179. // System.err.println(
  180. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  181. // +
  182. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  183. } else {
  184. Attribute[] attrs = bcelMethod.getAttributes();
  185. for (Attribute attribute : attrs) {
  186. if (attribute.getName().equals("AnnotationDefault")) {
  187. AnnotationDefault def = (AnnotationDefault) attribute;
  188. return def.getElementValue().stringifyValue();
  189. }
  190. }
  191. return null;
  192. }
  193. }
  194. } catch (ClassNotFoundException cnfEx) {
  195. // just use reflection then
  196. }
  197. return null;
  198. }
  199. public ResolvedType[] getAnnotations(Member onMember, boolean areRuntimeAnnotationsSufficient) {
  200. if (!(onMember instanceof AccessibleObject)) {
  201. return ResolvedType.NONE;
  202. }
  203. // If annotations with class level retention are required then we need to open
  204. // open the class file. If only runtime retention annotations are required
  205. // we can just use reflection.
  206. if (!areRuntimeAnnotationsSufficient) {
  207. try {
  208. JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
  209. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = null;
  210. if (onMember instanceof Method) {
  211. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  212. if (bcelMethod != null) {
  213. anns = bcelMethod.getAnnotations();
  214. }
  215. } else if (onMember instanceof Constructor) {
  216. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor<?>) onMember);
  217. anns = bcelCons.getAnnotations();
  218. } else if (onMember instanceof Field) {
  219. org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
  220. anns = bcelField.getAnnotations();
  221. }
  222. // the answer is cached and we don't want to hold on to memory
  223. getBcelRepository().clear();
  224. if (anns == null || anns.length == 0) {
  225. return ResolvedType.NONE;
  226. }
  227. ResolvedType[] annotationTypes = new ResolvedType[anns.length];
  228. for (int i = 0; i < anns.length; i++) {
  229. annotationTypes[i] = world.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()));
  230. }
  231. return annotationTypes;
  232. } catch (ClassNotFoundException cnfEx) {
  233. // just use reflection then
  234. }
  235. }
  236. AccessibleObject ao = (AccessibleObject) onMember;
  237. Annotation[] anns = ao.getDeclaredAnnotations();
  238. if (anns.length == 0) {
  239. return ResolvedType.NONE;
  240. }
  241. ResolvedType[] annotationTypes = new ResolvedType[anns.length];
  242. for (int i = 0; i < anns.length; i++) {
  243. annotationTypes[i] = UnresolvedType.forName(anns[i].annotationType().getName()).resolve(world);
  244. }
  245. return annotationTypes;
  246. }
  247. public ResolvedType[] getAnnotations(Class forClass, World inWorld) {
  248. // here we really want both the runtime visible AND the class visible
  249. // annotations so we bail out to Bcel and then chuck away the JavaClass so that we
  250. // don't hog memory.
  251. try {
  252. JavaClass jc = getBcelRepository().loadClass(forClass);
  253. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations();
  254. getBcelRepository().clear();
  255. if (anns == null) {
  256. return ResolvedType.NONE;
  257. } else {
  258. ResolvedType[] ret = new ResolvedType[anns.length];
  259. for (int i = 0; i < ret.length; i++) {
  260. ret[i] = inWorld.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()));
  261. }
  262. return ret;
  263. }
  264. } catch (ClassNotFoundException cnfEx) {
  265. // just use reflection then
  266. }
  267. Annotation[] classAnnotations = forClass.getAnnotations();
  268. ResolvedType[] ret = new ResolvedType[classAnnotations.length];
  269. for (int i = 0; i < classAnnotations.length; i++) {
  270. ret[i] = inWorld.resolve(classAnnotations[i].annotationType().getName());
  271. }
  272. return ret;
  273. }
  274. public String[] getParameterNames(Member forMember) {
  275. if (!(forMember instanceof AccessibleObject))
  276. return null;
  277. try {
  278. JavaClass jc = getBcelRepository().loadClass(forMember.getDeclaringClass());
  279. LocalVariableTable lvt = null;
  280. int numVars = 0;
  281. if (forMember instanceof Method) {
  282. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) forMember);
  283. lvt = bcelMethod.getLocalVariableTable();
  284. numVars = bcelMethod.getArgumentTypes().length;
  285. } else if (forMember instanceof Constructor) {
  286. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor<?>) forMember);
  287. lvt = bcelCons.getLocalVariableTable();
  288. numVars = bcelCons.getArgumentTypes().length;
  289. }
  290. return getParameterNamesFromLVT(lvt, numVars);
  291. } catch (ClassNotFoundException cnfEx) {
  292. ; // no luck
  293. }
  294. return null;
  295. }
  296. private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) {
  297. if (lvt == null)
  298. return null;// pr222987 - prevent NPE
  299. LocalVariable[] vars = lvt.getLocalVariableTable();
  300. if (vars.length < numVars) {
  301. // basic error, we can't get the names...
  302. return null;
  303. }
  304. String[] ret = new String[numVars];
  305. for (int i = 0; i < numVars; i++) {
  306. ret[i] = vars[i + 1].getName();
  307. }
  308. return ret;
  309. }
  310. public ResolvedType[][] getParameterAnnotationTypes(Member onMember) {
  311. if (!(onMember instanceof AccessibleObject))
  312. return NO_PARAMETER_ANNOTATIONS;
  313. // here we really want both the runtime visible AND the class visible
  314. // annotations
  315. // so we bail out to Bcel and then chuck away the JavaClass so that we
  316. // don't hog
  317. // memory.
  318. try {
  319. JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
  320. org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
  321. if (onMember instanceof Method) {
  322. org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
  323. if (bcelMethod == null) {
  324. // pr220430
  325. // System.err.println(
  326. // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
  327. // +
  328. // onMember.getName()+"' in class '"+jc.getClassName()+"'");
  329. } else {
  330. anns = bcelMethod.getParameterAnnotations();
  331. }
  332. } else if (onMember instanceof Constructor) {
  333. org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor<?>) onMember);
  334. anns = bcelCons.getParameterAnnotations();
  335. } else if (onMember instanceof Field) {
  336. // anns = null;
  337. }
  338. // the answer is cached and we don't want to hold on to memory
  339. getBcelRepository().clear();
  340. if (anns == null)
  341. return NO_PARAMETER_ANNOTATIONS;
  342. ResolvedType[][] result = new ResolvedType[anns.length][];
  343. // CACHING??
  344. for (int i = 0; i < anns.length; i++) {
  345. if (anns[i] != null) {
  346. result[i] = new ResolvedType[anns[i].length];
  347. for (int j = 0; j < anns[i].length; j++) {
  348. result[i][j] = world.resolve(UnresolvedType.forSignature(anns[i][j].getTypeSignature()));
  349. }
  350. }
  351. }
  352. return result;
  353. } catch (ClassNotFoundException cnfEx) {
  354. // just use reflection then
  355. }
  356. // reflection...
  357. AccessibleObject ao = (AccessibleObject) onMember;
  358. Annotation[][] anns = null;
  359. if (onMember instanceof Method) {
  360. anns = ((Method) ao).getParameterAnnotations();
  361. } else if (onMember instanceof Constructor) {
  362. anns = ((Constructor<?>) ao).getParameterAnnotations();
  363. } else if (onMember instanceof Field) {
  364. // anns = null;
  365. }
  366. if (anns == null)
  367. return NO_PARAMETER_ANNOTATIONS;
  368. ResolvedType[][] result = new ResolvedType[anns.length][];
  369. // CACHING??
  370. for (int i = 0; i < anns.length; i++) {
  371. if (anns[i] != null) {
  372. result[i] = new ResolvedType[anns[i].length];
  373. for (int j = 0; j < anns[i].length; j++) {
  374. result[i][j] = UnresolvedType.forName(anns[i][j].annotationType().getName()).resolve(world);
  375. }
  376. }
  377. }
  378. return result;
  379. }
  380. }