選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

Java15AnnotationFinder.java 15KB

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