/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.lang;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.Descriptor;
import javassist.bytecode.annotation.AnnotationImpl;
import javassist.scopedpool.ScopedClassPoolRepository;
import javassist.scopedpool.ScopedClassPoolRepositoryImpl;
/**
* AnnotationHelper.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 201 $
*/
public class AnnotationHelper
{
/** @todo Per classloader */
private static final ScopedClassPoolRepository repository = ScopedClassPoolRepositoryImpl.getInstance();
/**
* Whether an annotation is present
*
* @param clazz the class
* @param annotationClass the annotation class
* @return true when the annotation is present
*/
public static boolean isAnnotationPresent(Class clazz, Class annotationClass)
{
return getAnnotation(clazz, annotationClass) != null;
}
/**
* Get an annotation
*
* @param clazz the class
* @param annotationClass the annotation class
* @return the annotation
*/
public static Annotation getAnnotation(Class clazz, Class annotationClass)
{
if (annotationClass == null)
throw new NullPointerException("Null annotation");
String searchName = annotationClass.getName();
for (Object annotation : getAnnotationsInternal(clazz))
{
AnnotationImpl impl = (AnnotationImpl) Proxy.getInvocationHandler(annotation);
if (searchName.equals(impl.getTypeName()))
return (Annotation)annotation;
}
return null;
}
/**
* Get annotations
*
* @param clazz the class
* @return the annotations
*/
public static Annotation[] getAnnotations(Class clazz)
{
return convertAnnotationArray(getAnnotationsInternal(clazz));
}
static Object[] getAnnotationsInternal(Class clazz)
{
return getCtClass(clazz).getAvailableAnnotations();
}
/**
* Get declared annotations
*
* @param clazz the class
* @return the annotations
*/
public static Annotation[] getDeclaredAnnotations(Class clazz)
{
return convertAnnotationArray(getDeclaredAnnotationsInternal(clazz));
}
static Object[] getDeclaredAnnotationsInternal(Class clazz)
{
return getCtClass(clazz).getAvailableAnnotations();
}
/**
* Get the javassist class
*
* @param clazz the class
* @return the javassist method
*/
static CtClass getCtClass(Class clazz)
{
try
{
ClassPool pool = repository.findClassPool(clazz.getClassLoader());
return pool.get(clazz.getName());
}
catch (NotFoundException e)
{
throw new RuntimeException("Unable to load CtClass for " + clazz, e);
}
}
/**
* Whether an annotation is present
*
* @param ao the accessible object
* @param annotationClass the annotation class
* @return true when the annotation is present
*/
public static boolean isAnnotationPresent(Object obj, Class annotationClass)
{
if (obj instanceof Class)
{
return isAnnotationPresent((Class)obj, annotationClass);
}
else if (obj instanceof Method)
{
return isAnnotationPresent((Method)obj, annotationClass);
}
else if (obj instanceof Constructor)
{
return isAnnotationPresent((Constructor)obj, annotationClass);
}
else if (obj instanceof Field)
{
return isAnnotationPresent((Field)obj, annotationClass);
}
//Should not happen
throw new RuntimeException("Invalid AccessibleObject passed in " + obj);
}
/**
* Get an annotation
*
* @param ao the accessible object
* @param annotationClass the annotation class
* @return the annotation
*/
public static Annotation getAnnotation(AccessibleObject ao, Class annotationClass)
{
if (ao instanceof Method)
{
return getAnnotation((Method)ao, annotationClass);
}
else if (ao instanceof Constructor)
{
return getAnnotation((Constructor)ao, annotationClass);
}
else if (ao instanceof Field)
{
return getAnnotation((Field)ao, annotationClass);
}
//Should not happen
throw new RuntimeException("Invalid AccessibleObject passed in " + ao);
}
/**
* Get annotations
*
* @param ao the accessible object
* @return the annotations
*/
public static Annotation[] getAnnotations(AccessibleObject ao)
{
if (ao instanceof Method)
{
return getAnnotations((Method)ao);
}
else if (ao instanceof Constructor)
{
return getAnnotations((Constructor)ao);
}
else if (ao instanceof Field)
{
return getAnnotations((Field)ao);
}
//Should not happen
throw new RuntimeException("Invalid AccessibleObject passed in " + ao);
}
/**
* Get declared annotations
*
* @param ao the accessible object
* @return the annotations
*/
public static Annotation[] getDeclaredAnnotations(AccessibleObject ao)
{
if (ao instanceof Method)
{
return getDeclaredAnnotations((Method)ao);
}
else if (ao instanceof Constructor)
{
return getDeclaredAnnotations((Constructor)ao);
}
else if (ao instanceof Field)
{
return getDeclaredAnnotations((Field)ao);
}
//Should not happen
throw new RuntimeException("Invalid AccessibleObject passed in " + ao);
}
/**
* Whether an annotation is present
*
* @param method the method
* @param annotationClass the annotation class
* @return true when the annotation is present
*/
public static boolean isAnnotationPresent(Method method, Class annotationClass)
{
return getAnnotation(method, annotationClass) != null;
}
/**
* Get an annotation
*
* @param method the method
* @param annotationClass the annotation class
* @return the annotation
*/
public static Annotation getAnnotation(Method method, Class annotationClass)
{
if (annotationClass == null)
throw new NullPointerException("Null annotation");
String searchName = annotationClass.getName();
for (Object annotation : getAnnotationsInternal(method))
{
AnnotationImpl impl = (AnnotationImpl) Proxy.getInvocationHandler(annotation);
if (searchName.equals(impl.getTypeName()))
return (Annotation)annotation;
}
return null;
}
/**
* Get an array of the annotations attached to this element.
* TODO: currently does not include inherited annotations, this should be added.
* @return
*/
public static Annotation[] getAnnotations(Object object)
{
if (object instanceof Class)
{
return convertAnnotationArray(getAnnotationsInternal((Class) object));
}
if (object instanceof Constructor)
{
return convertAnnotationArray(getAnnotationsInternal((Constructor) object));
}
if (object instanceof Field)
{
return convertAnnotationArray(getAnnotationsInternal((Field) object));
}
if (object instanceof Method)
{
return convertAnnotationArray(getAnnotationsInternal((Method) object));
}
//TODO: package annotations should be handled here.
/*if (object instanceof Package)
{
return convertAnnotationArray(getAnnotationsInternal((Package) object));
}*/
return new Annotation[0];
}
/**
* Get an array of the annotations attached to this element.
* (Includes inherited annotations) TODO: this should not include inherited annotations.
* @return
*/
public static Annotation[] getDeclaredAnnotations(Object object)
{
if (object instanceof Class)
{
return convertAnnotationArray(getDeclaredAnnotations((Class) object));
}
if (object instanceof Constructor)
{
return convertAnnotationArray(getDeclaredAnnotations((Constructor) object));
}
if (object instanceof Field)
{
return convertAnnotationArray(getDeclaredAnnotations((Field) object));
}
if (object instanceof Method)
{
return convertAnnotationArray(getAnnotationsInternal((Method) object));
}
/*if (object instanceof Package)
{
return convertAnnotationArray(getAnnotationsInternal((Package) object));
}*/
return new Annotation[0];
}
/**
* Get an annotation
*
* @param object the the annotated element
* @param annotationClass the annotation class
* @return the annotation
*/
public static Annotation getAnnotation(Object object, Class annotationClass)
{
if (object instanceof Class)
{
return getAnnotation((Class)object, annotationClass);
}
if (object instanceof Constructor)
{
return getAnnotation((Constructor)object, annotationClass);
}
if (object instanceof Field)
{
return getAnnotation((Field)object, annotationClass);
}
if (object instanceof Method)
{
return getAnnotation((Method)object, annotationClass);
}
/*if (object instanceof Package)
{
return getAnnotation((Package)object, annotationClass);
}*/
return null;
}
/**
* Get annotations
*
* @param method the method
* @return the annotations
*/
public static Annotation[] getAnnotations(Method method)
{
return convertAnnotationArray(getAnnotationsInternal(method));
}
public static Object[] getAnnotationsInternal(Method method)
{
return getCtMethod(method).getAvailableAnnotations();
}
/**
* Get declared annotations
*
* @param method the method
* @return the annotations
*/
public static Annotation[] getDeclaredAnnotations(Method method)
{
return convertAnnotationArray(getAnnotationsInternal(method));
}
public static Object[] getDeclaredAnnotationsInternal(Method method)
{
return getCtMethod(method).getAvailableAnnotations();
}
/**
* Get the parameter annotations
*
* @param method the method
* @return the annotations
*/
public static Annotation[][] getParameterAnnotations(Method method)
{
return convertAnnotationArray(getCtMethod(method).getAvailableParameterAnnotations());
}
/**
* Get the javassist method
*
* @param method the method
* @return the javassist method
*/
static CtMethod getCtMethod(Method method)
{
CtClass clazz = getCtClass(method.getDeclaringClass());
Class[] parameters = method.getParameterTypes();
CtClass[] params = new CtClass[parameters.length];
for (int i = 0; i < parameters.length; ++i)
params[i] = getCtClass(parameters[i]);
CtClass returnType = getCtClass(method.getReturnType());
String descriptor = Descriptor.ofMethod(returnType, params);
try
{
return clazz.getMethod(method.getName(), descriptor);
}
catch (NotFoundException e)
{
throw new RuntimeException("Unable to find method " + method + " descriptor=" + descriptor, e);
}
}
/**
* Whether an annotation is present
*
* @param constructor the constructor
* @param annotationClass the annotation class
* @return true when the annotation is present
*/
public static boolean isAnnotationPresent(Constructor constructor, Class annotationClass)
{
return getAnnotation(constructor, annotationClass) != null;
}
/**
* Get an annotation
*
* @param constructor the constructor
* @param annotationClass the annotation class
* @return the annotation
*/
public static Annotation getAnnotation(Constructor constructor, Class annotationClass)
{
if (annotationClass == null)
throw new NullPointerException("Null annotation");
String searchName = annotationClass.getName();
for (Object annotation : getAnnotationsInternal(constructor))
{
AnnotationImpl impl = (AnnotationImpl) Proxy.getInvocationHandler(annotation);
if (searchName.equals(impl.getTypeName()))
return (Annotation)annotation;
}
return null;
}
/**
* Get annotations
*
* @param constructor the constructor
* @return the annotations
*/
public static Annotation[] getAnnotations(Constructor constructor)
{
return convertAnnotationArray(getAnnotationsInternal(constructor));
}
static Object[] getAnnotationsInternal(Constructor constructor)
{
return getCtConstructor(constructor).getAvailableAnnotations();
}
/**
* Get declared annotations
*
* @param constructor the constructor
* @return the annotations
*/
public static Annotation[] getDeclaredAnnotations(Constructor constructor)
{
return convertAnnotationArray(getDeclaredAnnotationsInternal(constructor));
}
static Object[] getDeclaredAnnotationsInternal(Constructor constructor)
{
return getCtConstructor(constructor).getAvailableAnnotations();
}
/**
* Get the parameter annotations
*
* @param constructor the constructor
* @return the annotations
*/
public static Annotation[][] getParameterAnnotations(Constructor constructor)
{
return convertAnnotationArray(getCtConstructor(constructor).getAvailableParameterAnnotations());
}
/**
* Get the javassist constructor
*
* @param constructor the constructor
* @return the javassist constructor
*/
static CtConstructor getCtConstructor(Constructor constructor)
{
CtClass clazz = getCtClass(constructor.getDeclaringClass());
Class[] parameters = constructor.getParameterTypes();
CtClass[] params = new CtClass[parameters.length];
for (int i = 0; i < parameters.length; ++i)
params[i] = getCtClass(parameters[i]);
String descriptor = Descriptor.ofConstructor(params);
try
{
return clazz.getConstructor(descriptor);
}
catch (NotFoundException e)
{
throw new RuntimeException("Unable to find constructor descriptor=" + descriptor, e);
}
}
/**
* Whether an annotation is present
*
* @param field the field
* @param annotationClass the annotation class
* @return true when the annotation is present
*/
public static boolean isAnnotationPresent(Field field, Class annotationClass)
{
return getAnnotation(field, annotationClass) != null;
}
/**
* Get an annotation
*
* @param field the field
* @param annotationClass the annotation class
* @return the annotation
*/
public static Annotation getAnnotation(Field field, Class annotationClass)
{
if (annotationClass == null)
throw new NullPointerException("Null annotation");
String searchName = annotationClass.getName();
for (Object annotation : getAnnotationsInternal(field))
{
AnnotationImpl impl = (AnnotationImpl) Proxy.getInvocationHandler(annotation);
if (searchName.equals(impl.getTypeName()))
return (Annotation)annotation;
}
return null;
}
/**
* Get annotations
*
* @param field the field
* @return the annotations
*/
public static Annotation[] getAnnotations(Field field)
{
return convertAnnotationArray(getAnnotationsInternal(field));
}
static Object[] getAnnotationsInternal(Field field)
{
return getCtField(field).getAvailableAnnotations();
}
/**
* Get declared annotations
*
* @param field the field
* @return the annotations
*/
public static Annotation[] getDeclaredAnnotations(Field field)
{
return convertAnnotationArray(getDeclaredAnnotationsInternal(field));
}
static Object[] getDeclaredAnnotationsInternal(Field field)
{
return getCtField(field).getAvailableAnnotations();
}
/**
* Get the javassist field
*
* @param field the field
* @return the javassist field
*/
static CtField getCtField(Field field)
{
CtClass clazz = getCtClass(field.getDeclaringClass());
try
{
return clazz.getField(field.getName());
}
catch (NotFoundException e)
{
throw new RuntimeException("Unable to find field " + field, e);
}
}
static Annotation[] convertAnnotationArray(Object[] annotations)
{
Annotation[] anns = new Annotation[annotations.length];
for (int i = 0 ; i < annotations.length ; i++)
{
anns[i] = (Annotation)annotations[i];
}
return anns;
}
static Annotation[][] convertAnnotationArray(Object[][] annotations)
{
Annotation[][] anns = new Annotation[annotations.length][];
for (int i = 0 ; i < annotations.length ; i++)
{
anns[i] = new Annotation[annotations[i].length];
for (int j = 0 ; j < annotations[i].length ; j++)
{
anns[i][j] = (Annotation)annotations[i][j];
}
}
return anns;
}
/**
* Static helper class
*/
private AnnotationHelper()
{
}
}