123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /* *******************************************************************
- * Copyright (c) 2005, 2017 Contributors.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://eclipse.org/legal/epl-v10.html
- * ******************************************************************/
- package org.aspectj.weaver.reflect;
-
- import java.lang.annotation.Annotation;
- import java.lang.reflect.AccessibleObject;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Member;
- import java.lang.reflect.Method;
-
- import org.aspectj.apache.bcel.classfile.AnnotationDefault;
- import org.aspectj.apache.bcel.classfile.Attribute;
- import org.aspectj.apache.bcel.classfile.JavaClass;
- import org.aspectj.apache.bcel.classfile.LocalVariable;
- import org.aspectj.apache.bcel.classfile.LocalVariableTable;
- import org.aspectj.apache.bcel.util.ClassLoaderRepository;
- import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository;
- import org.aspectj.apache.bcel.util.Repository;
- import org.aspectj.weaver.AnnotationAJ;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.World;
- import org.aspectj.weaver.bcel.BcelAnnotation;
- import org.aspectj.weaver.bcel.BcelWeakClassLoaderReference;
-
- /**
- *
- * @author Adrian Colyer
- * @author Andy Clement
- */
- public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
-
- public static final ResolvedType[][] NO_PARAMETER_ANNOTATIONS = new ResolvedType[][] {};
-
- private Repository bcelRepository;
- private BcelWeakClassLoaderReference classLoaderRef;
- private World world;
- private static boolean useCachingClassLoaderRepository;
-
- static {
- try {
- useCachingClassLoaderRepository = System.getProperty("Xset:bcelRepositoryCaching","true").equalsIgnoreCase("true");
- } catch (Throwable t) {
- useCachingClassLoaderRepository = false;
- }
- }
-
- // must have no-arg constructor for reflective construction
- public Java15AnnotationFinder() {
- }
-
- public void setClassLoader(ClassLoader aLoader) {
- this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
- if (useCachingClassLoaderRepository) {
- this.bcelRepository = new ClassLoaderRepository(classLoaderRef);
- } else {
- this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
- }
- }
-
- public void setWorld(World aWorld) {
- this.world = aWorld;
- }
-
- public Object getAnnotation(ResolvedType annotationType, Object onObject) {
- try {
- Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
- false, getClassLoader());
- if (onObject.getClass().isAnnotationPresent(annotationClass)) {
- return onObject.getClass().getAnnotation(annotationClass);
- }
- } catch (ClassNotFoundException ex) {
- // just return null
- }
- return null;
- }
-
- public Object getAnnotationFromClass(ResolvedType annotationType, Class aClass) {
- try {
- Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(annotationType.getName(),
- false, getClassLoader());
- if (aClass.isAnnotationPresent(annotationClass)) {
- return aClass.getAnnotation(annotationClass);
- }
- } catch (ClassNotFoundException ex) {
- // just return null
- }
- return null;
- }
-
- public Object getAnnotationFromMember(ResolvedType annotationType, Member aMember) {
- if (!(aMember instanceof AccessibleObject))
- return null;
- AccessibleObject ao = (AccessibleObject) aMember;
- try {
- Class annotationClass = Class.forName(annotationType.getName(), false, getClassLoader());
- if (ao.isAnnotationPresent(annotationClass)) {
- return ao.getAnnotation(annotationClass);
- }
- } catch (ClassNotFoundException ex) {
- // just return null
- }
- return null;
- }
-
- private ClassLoader getClassLoader() {
- return classLoaderRef.getClassLoader();
- }
-
- public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) {
- if (!(onMember instanceof AccessibleObject))
- return null;
- // here we really want both the runtime visible AND the class visible
- // annotations
- // so we bail out to Bcel and then chuck away the JavaClass so that we
- // don't hog
- // memory.
- try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
- org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
- if (onMember instanceof Method) {
- org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
- if (bcelMethod == null) {
- // pr220430
- // System.err.println(
- // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
- // +
- // onMember.getName()+"' in class '"+jc.getClassName()+"'");
- } else {
- anns = bcelMethod.getAnnotations();
- }
- } else if (onMember instanceof Constructor) {
- org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
- anns = bcelCons.getAnnotations();
- } else if (onMember instanceof Field) {
- org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
- anns = bcelField.getAnnotations();
- }
- // the answer is cached and we don't want to hold on to memory
- bcelRepository.clear();
- // OPTIMIZE make constant 0 size array for sharing
- if (anns == null)
- anns = new org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[0];
- // convert to our Annotation type
- for (int i = 0; i < anns.length; i++) {
- if (anns[i].getTypeSignature().equals(ofType.getSignature())) {
- return new BcelAnnotation(anns[i], world);
- }
- }
- return null;
- } catch (ClassNotFoundException cnfEx) {
- // just use reflection then
- }
- return null;
- }
-
- public String getAnnotationDefaultValue(Member onMember) {
- try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
- if (onMember instanceof Method) {
- org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
-
- if (bcelMethod == null) {
- // pr220430
- // System.err.println(
- // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
- // +
- // onMember.getName()+"' in class '"+jc.getClassName()+"'");
- } else {
- Attribute[] attrs = bcelMethod.getAttributes();
- for (int i = 0; i < attrs.length; i++) {
- Attribute attribute = attrs[i];
- if (attribute.getName().equals("AnnotationDefault")) {
- AnnotationDefault def = (AnnotationDefault) attribute;
- return def.getElementValue().stringifyValue();
- }
- }
- return null;
- }
- }
- } catch (ClassNotFoundException cnfEx) {
- // just use reflection then
- }
- return null;
- }
-
- public ResolvedType[] getAnnotations(Member onMember, boolean areRuntimeAnnotationsSufficient) {
- if (!(onMember instanceof AccessibleObject)) {
- return ResolvedType.NONE;
- }
- // If annotations with class level retention are required then we need to open
- // open the class file. If only runtime retention annotations are required
- // we can just use reflection.
- if (!areRuntimeAnnotationsSufficient) {
- try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
- org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = null;
- if (onMember instanceof Method) {
- org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
- if (bcelMethod != null) {
- anns = bcelMethod.getAnnotations();
- }
- } else if (onMember instanceof Constructor) {
- org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
- anns = bcelCons.getAnnotations();
- } else if (onMember instanceof Field) {
- org.aspectj.apache.bcel.classfile.Field bcelField = jc.getField((Field) onMember);
- anns = bcelField.getAnnotations();
- }
- // the answer is cached and we don't want to hold on to memory
- bcelRepository.clear();
- if (anns == null || anns.length == 0) {
- return ResolvedType.NONE;
- }
- ResolvedType[] annotationTypes = new ResolvedType[anns.length];
- for (int i = 0; i < anns.length; i++) {
- annotationTypes[i] = world.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()));
- }
- return annotationTypes;
- } catch (ClassNotFoundException cnfEx) {
- // just use reflection then
- }
- }
-
- AccessibleObject ao = (AccessibleObject) onMember;
- Annotation[] anns = ao.getDeclaredAnnotations();
- if (anns.length == 0) {
- return ResolvedType.NONE;
- }
- ResolvedType[] annotationTypes = new ResolvedType[anns.length];
- for (int i = 0; i < anns.length; i++) {
- annotationTypes[i] = UnresolvedType.forName(anns[i].annotationType().getName()).resolve(world);
- }
- return annotationTypes;
- }
-
- public ResolvedType[] getAnnotations(Class forClass, World inWorld) {
- // here we really want both the runtime visible AND the class visible
- // annotations so we bail out to Bcel and then chuck away the JavaClass so that we
- // don't hog memory.
- try {
- JavaClass jc = bcelRepository.loadClass(forClass);
- org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations();
- bcelRepository.clear();
- if (anns == null) {
- return ResolvedType.NONE;
- } else {
- ResolvedType[] ret = new ResolvedType[anns.length];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = inWorld.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()));
- }
- return ret;
- }
- } catch (ClassNotFoundException cnfEx) {
- // just use reflection then
- }
-
- Annotation[] classAnnotations = forClass.getAnnotations();
- ResolvedType[] ret = new ResolvedType[classAnnotations.length];
- for (int i = 0; i < classAnnotations.length; i++) {
- ret[i] = inWorld.resolve(classAnnotations[i].annotationType().getName());
- }
-
- return ret;
- }
-
- public String[] getParameterNames(Member forMember) {
- if (!(forMember instanceof AccessibleObject))
- return null;
-
- try {
- JavaClass jc = bcelRepository.loadClass(forMember.getDeclaringClass());
- LocalVariableTable lvt = null;
- int numVars = 0;
- if (forMember instanceof Method) {
- org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) forMember);
- lvt = bcelMethod.getLocalVariableTable();
- numVars = bcelMethod.getArgumentTypes().length;
- } else if (forMember instanceof Constructor) {
- org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) forMember);
- lvt = bcelCons.getLocalVariableTable();
- numVars = bcelCons.getArgumentTypes().length;
- }
- return getParameterNamesFromLVT(lvt, numVars);
- } catch (ClassNotFoundException cnfEx) {
- ; // no luck
- }
-
- return null;
- }
-
- private String[] getParameterNamesFromLVT(LocalVariableTable lvt, int numVars) {
- if (lvt == null)
- return null;// pr222987 - prevent NPE
- LocalVariable[] vars = lvt.getLocalVariableTable();
- if (vars.length < numVars) {
- // basic error, we can't get the names...
- return null;
- }
- String[] ret = new String[numVars];
- for (int i = 0; i < numVars; i++) {
- ret[i] = vars[i + 1].getName();
- }
- return ret;
- }
-
- public ResolvedType[][] getParameterAnnotationTypes(Member onMember) {
- if (!(onMember instanceof AccessibleObject))
- return NO_PARAMETER_ANNOTATIONS;
- // here we really want both the runtime visible AND the class visible
- // annotations
- // so we bail out to Bcel and then chuck away the JavaClass so that we
- // don't hog
- // memory.
- try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
- org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
- if (onMember instanceof Method) {
- org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
- if (bcelMethod == null) {
- // pr220430
- // System.err.println(
- // "Unexpected problem in Java15AnnotationFinder: cannot retrieve annotations on method '"
- // +
- // onMember.getName()+"' in class '"+jc.getClassName()+"'");
- } else {
- anns = bcelMethod.getParameterAnnotations();
- }
- } else if (onMember instanceof Constructor) {
- org.aspectj.apache.bcel.classfile.Method bcelCons = jc.getMethod((Constructor) onMember);
- anns = bcelCons.getParameterAnnotations();
- } else if (onMember instanceof Field) {
- // anns = null;
- }
- // the answer is cached and we don't want to hold on to memory
- bcelRepository.clear();
- if (anns == null)
- return NO_PARAMETER_ANNOTATIONS;
- ResolvedType[][] result = new ResolvedType[anns.length][];
- // CACHING??
- for (int i = 0; i < anns.length; i++) {
- if (anns[i] != null) {
- result[i] = new ResolvedType[anns[i].length];
- for (int j = 0; j < anns[i].length; j++) {
- result[i][j] = world.resolve(UnresolvedType.forSignature(anns[i][j].getTypeSignature()));
- }
- }
- }
- return result;
- } catch (ClassNotFoundException cnfEx) {
- // just use reflection then
- }
-
- // reflection...
- AccessibleObject ao = (AccessibleObject) onMember;
- Annotation[][] anns = null;
- if (onMember instanceof Method) {
- anns = ((Method) ao).getParameterAnnotations();
- } else if (onMember instanceof Constructor) {
- anns = ((Constructor) ao).getParameterAnnotations();
- } else if (onMember instanceof Field) {
- // anns = null;
- }
- if (anns == null)
- return NO_PARAMETER_ANNOTATIONS;
- ResolvedType[][] result = new ResolvedType[anns.length][];
- // CACHING??
- for (int i = 0; i < anns.length; i++) {
- if (anns[i] != null) {
- result[i] = new ResolvedType[anns[i].length];
- for (int j = 0; j < anns[i].length; j++) {
- result[i][j] = UnresolvedType.forName(anns[i][j].annotationType().getName()).resolve(world);
- }
- }
- }
- return result;
- }
-
- }
|