/* ******************************************************************* * Copyright (c) 2005 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 * * Contributors: * Adrian Colyer Initial implementation * ******************************************************************/ 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 java.util.Collections; import java.util.HashSet; import java.util.Set; 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.NonCachingClassLoaderRepository; import org.aspectj.apache.bcel.util.Repository; import org.aspectj.apache.bcel.util.ClassLoaderRepository; import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.World; /** * Find the given annotation (if present) on the given object * */ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder { private Repository bcelRepository; private ClassLoader classLoader; private World world; // must have no-arg constructor for reflective construction public Java15AnnotationFinder() { } public void setClassLoader(ClassLoader aLoader) { // TODO: No easy way to ask the world factory for the right kind of repository so // default to the safe one! (pr160674) this.bcelRepository = new NonCachingClassLoaderRepository(aLoader); this.classLoader = aLoader; } public void setWorld(World aWorld) { this.world = aWorld; } /* (non-Javadoc) * @see org.aspectj.weaver.reflect.AnnotationFinder#getAnnotation(org.aspectj.weaver.ResolvedType, java.lang.Object) */ public Object getAnnotation(ResolvedType annotationType, Object onObject) { try { Class annotationClass = (Class) Class.forName(annotationType.getName(),false,classLoader); 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 annotationClass = (Class) Class.forName(annotationType.getName(),false,classLoader); 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,classLoader); if (ao.isAnnotationPresent(annotationClass)) { return ao.getAnnotation(annotationClass); } } catch (ClassNotFoundException ex) { // just return null } return null; } public Set getAnnotations(Member onMember) { if (!(onMember instanceof AccessibleObject)) return Collections.EMPTY_SET; // 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.Annotation[] anns = new org.aspectj.apache.bcel.classfile.annotation.Annotation[0]; if (onMember instanceof Method) { org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method)onMember); 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 = new org.aspectj.apache.bcel.classfile.annotation.Annotation[0]; // convert to our Annotation type Set annSet = new HashSet(); for (int i = 0; i < anns.length; i++) { annSet.add(world.resolve(UnresolvedType.forSignature(anns[i].getTypeSignature()))); } return annSet; } catch (ClassNotFoundException cnfEx) { // just use reflection then } AccessibleObject ao = (AccessibleObject) onMember; Annotation[] anns = ao.getDeclaredAnnotations(); Set annSet = new HashSet(); for (int i = 0; i < anns.length; i++) { annSet.add(UnresolvedType.forName(anns[i].annotationType().getName()).resolve(world)); } return annSet; } 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.Annotation[] anns =jc.getAnnotations(); bcelRepository.clear(); if (anns == null) return new ResolvedType[0]; 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) { 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; } }