
org.mortbay.jetty.annotations.AnnotationFinder Maven / Gradle / Ivy
The newest version!
// ========================================================================
// $Id: AnnotationFinder.java 3353 2008-07-22 10:39:41Z janb $
// Copyright 2008 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.mortbay.jetty.annotations;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.regex.Pattern;
import org.mortbay.jetty.webapp.JarScanner;
import org.mortbay.log.Log;
import org.mortbay.resource.Resource;
import org.mortbay.util.Loader;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
/**
* AnnotationFinder
*
*
* Scans class sources using asm to find annotations.
*
*
*/
public class AnnotationFinder
{
private Map parsedClasses = new HashMap();
public static String normalize (String name)
{
if (name==null)
return null;
if (name.startsWith("L") && name.endsWith(";"))
name = name.substring(1, name.length()-1);
if (name.endsWith(".class"))
name = name.substring(0, name.length()-".class".length());
name = name.replace('$', '.');
return name.replace('/', '.');
}
public static Class convertType (org.objectweb.asm.Type t)
throws Exception
{
if (t == null)
return (Class)null;
switch (t.getSort())
{
case Type.BOOLEAN:
{
return Boolean.TYPE;
}
case Type.ARRAY:
{
Class clazz = convertType(t.getElementType());
return Array.newInstance(clazz, 0).getClass();
}
case Type.BYTE:
{
return Byte.TYPE;
}
case Type.CHAR:
{
return Character.TYPE;
}
case Type.DOUBLE:
{
return Double.TYPE;
}
case Type.FLOAT:
{
return Float.TYPE;
}
case Type.INT:
{
return Integer.TYPE;
}
case Type.LONG:
{
return Long.TYPE;
}
case Type.OBJECT:
{
return (Loader.loadClass(null, t.getClassName()));
}
case Type.SHORT:
{
return Short.TYPE;
}
case Type.VOID:
{
return null;
}
default:
return null;
}
}
public static Class[] convertTypes (Type[] types)
throws Exception
{
if (types==null)
return new Class[0];
Class[] classArray = new Class[types.length];
for (int i=0; i> annotations = new HashMap>();
public AnnotationVisitor addAnnotation (final String name)
{
final HashMap annotationValues = new HashMap();
this.annotations.put(normalize(name), annotationValues);
return new AnnotationVisitor()
{
public void visit(String name, Object value)
{
annotationValues.put(name, value);
}
public AnnotationVisitor visitAnnotation(String name, String desc)
{
return null; //ignore nested annotations
}
public AnnotationVisitor visitArray(String arg0)
{
return null;//ignore array valued annotations
}
public void visitEnd()
{
}
public void visitEnum(String name, String desc, String value)
{
}
};
}
public Map> getAnnotations ()
{
return annotations;
}
public String toString()
{
StringBuffer strbuff = new StringBuffer();
for (Map.Entry> e: annotations.entrySet())
{
strbuff.append(e.getKey()+"\n");
for (Map.Entry v: e.getValue().entrySet())
{
strbuff.append("\t"+v.getKey()+"="+v.getValue()+", ");
}
}
return strbuff.toString();
}
}
/**
* ParsedClass
*
* A class that contains annotations.
*/
public static class ParsedClass extends AnnotatedStructure
{
String className;
String superClassName;
Class clazz;
List methods = new ArrayList();
List fields = new ArrayList();
public ParsedClass (String className, String superClassName)
{
this.className = normalize(className);
this.superClassName = normalize(superClassName);
}
public String getClassName()
{
return this.className;
}
public String getSuperClassName ()
{
return this.superClassName;
}
public Class toClass ()
throws ClassNotFoundException
{
if (clazz==null)
clazz = Loader.loadClass(null, className);
return clazz;
}
public List getMethods ()
{
return methods;
}
public ParsedMethod getMethod(String name, String paramString)
{
Iterator itor = methods.iterator();
ParsedMethod method = null;
while (itor.hasNext() && method==null)
{
ParsedMethod m = itor.next();
if (m.matches(name, paramString))
method = m;
}
return method;
}
public void addMethod (ParsedMethod m)
{
if (getMethod(m.methodName, m.paramString)!= null)
return;
methods.add(m);
}
public List getFields()
{
return fields;
}
public ParsedField getField(String name)
{
Iterator itor = fields.iterator();
ParsedField field = null;
while (itor.hasNext() && field==null)
{
ParsedField f = itor.next();
if (f.matches(name))
field=f;
}
return field;
}
public void addField (ParsedField f)
{
if (getField(f.fieldName) != null)
return;
fields.add(f);
}
public String toString ()
{
StringBuffer strbuff = new StringBuffer();
strbuff.append(this.className+"\n");
strbuff.append("Class annotations\n"+super.toString());
strbuff.append("\n");
strbuff.append("Method annotations\n");
for (ParsedMethod p:methods)
strbuff.append(p+"\n");
strbuff.append("\n");
strbuff.append("Field annotations\n");
for (ParsedField f:fields)
strbuff.append(f+"\n");
strbuff.append("\n");
return strbuff.toString();
}
}
/**
* ParsedMethod
*
* A class method that can contain annotations.
*/
public static class ParsedMethod extends AnnotatedStructure
{
ParsedClass pclass;
String methodName;
String paramString;
Method method;
public ParsedMethod(ParsedClass pclass, String name, String paramString)
{
this.pclass=pclass;
this.methodName=name;
this.paramString=paramString;
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
{
this.pclass.addMethod(this);
return addAnnotation(desc);
}
public Method toMethod ()
throws Exception
{
if (method == null)
{
Type[] types = null;
if (paramString!=null)
types = Type.getArgumentTypes(paramString);
Class[] args = convertTypes(types);
method = pclass.toClass().getDeclaredMethod(methodName, args);
}
return method;
}
public boolean matches (String name, String paramString)
{
if (!methodName.equals(name))
return false;
if (this.paramString!=null && this.paramString.equals(paramString))
return true;
return (this.paramString == paramString);
}
public String toString ()
{
return pclass.getClassName()+"."+methodName+"\n\t"+super.toString();
}
}
/**
* ParsedField
*
* A class field that can contain annotations. Also implements the
* asm visitor for Annotations.
*/
public static class ParsedField extends AnnotatedStructure
{
ParsedClass pclass;
String fieldName;
Field field;
public ParsedField (ParsedClass pclass, String name)
{
this.pclass=pclass;
this.fieldName=name;
}
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
{
this.pclass.addField(this);
return addAnnotation(desc);
}
public Field toField ()
throws Exception
{
if (field==null)
{
field=this.pclass.toClass().getDeclaredField(fieldName);
}
return field;
}
public boolean matches (String name)
{
if (fieldName.equals(name))
return true;
return false;
}
public String toString ()
{
return pclass.getClassName()+"."+fieldName+"\n\t"+super.toString();
}
}
/**
* MyClassVisitor
*
* ASM visitor for a class.
*/
public class MyClassVisitor extends EmptyVisitor
{
ParsedClass pclass;
public void visit (int version,
int access,
String name,
String signature,
String superName,
String[] interfaces)
{
pclass = new ParsedClass(name, superName);
}
public AnnotationVisitor visitAnnotation (String desc, boolean visible)
{
if (!parsedClasses.containsKey(pclass.getClassName()))
parsedClasses.put(pclass.getClassName(), pclass);
return pclass.addAnnotation(desc);
}
public MethodVisitor visitMethod (int access,
String name,
String desc,
String signature,
String[] exceptions)
{
if (!parsedClasses.values().contains(pclass))
parsedClasses.put(pclass.getClassName(),pclass);
ParsedMethod method = pclass.getMethod(name, desc);
if (method==null)
method = new ParsedMethod(pclass, name, desc);
return method;
}
public FieldVisitor visitField (int access,
String name,
String desc,
String signature,
Object value)
{
if (!parsedClasses.values().contains(pclass))
parsedClasses.put(pclass.getClassName(),pclass);
ParsedField field = pclass.getField(name);
if (field==null)
field = new ParsedField(pclass, name);
return field;
}
}
public void find (String className, ClassNameResolver resolver)
throws Exception
{
if (className == null)
return;
if (!resolver.isExcluded(className))
{
if ((parsedClasses.get(className) == null) || (resolver.shouldOverride(className)))
{
parsedClasses.remove(className);
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(this.getClass(), className, false);
if (resource!= null)
scanClass(resource.openStream());
}
}
}
public void find (String[] classNames, ClassNameResolver resolver)
throws Exception
{
if (classNames == null)
return;
find(Arrays.asList(classNames), resolver);
}
public void find (List classNames, ClassNameResolver resolver)
throws Exception
{
for (String s:classNames)
{
if (!resolver.isExcluded(s))
{
if ((parsedClasses.get(s) == null) || (resolver.shouldOverride(s)))
{
parsedClasses.remove(s);
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(this.getClass(), s, false);
if (resource!= null)
scanClass(resource.openStream());
}
}
}
}
public void find (Resource dir, ClassNameResolver resolver)
throws Exception
{
if (!dir.isDirectory() || !dir.exists())
return;
String[] files=dir.list();
for (int f=0;files!=null && f> getClassesForAnnotation(Class> annotationClass)
throws Exception
{
List> classes = new ArrayList>();
for (Map.Entry e: parsedClasses.entrySet())
{
ParsedClass pc = e.getValue();
Map> annotations = pc.getAnnotations();
for (String key:annotations.keySet())
{
if (key.equals(annotationClass.getName()))
{
classes.add(pc.toClass());
}
}
}
return classes;
}
public List getMethodsForAnnotation (Class> annotationClass)
throws Exception
{
List methods = new ArrayList();
for (Map.Entry e: parsedClasses.entrySet())
{
ParsedClass pc = e.getValue();
List pmethods = pc.getMethods();
for (ParsedMethod p:pmethods)
{
for (String key:p.getAnnotations().keySet())
{
if (key.equals(annotationClass.getName()))
{
methods.add(p.toMethod());
}
}
}
}
return methods;
}
public List getFieldsForAnnotation (Class> annotation)
throws Exception
{
List fields = new ArrayList();
for (Map.Entry e: parsedClasses.entrySet())
{
ParsedClass pc = e.getValue();
List pfields = pc.getFields();
for (ParsedField f:pfields)
{
for (String key:f.getAnnotations().keySet())
{
if (key.equals(annotation.getName()))
{
fields.add(f.toField());
}
}
}
}
return fields;
}
public String toString ()
{
StringBuffer strbuff = new StringBuffer();
for (Map.Entry e:parsedClasses.entrySet())
{
strbuff.append(e.getValue());
strbuff.append("\n");
}
return strbuff.toString();
}
private void scanClass (InputStream is)
throws IOException
{
ClassReader reader = new ClassReader(is);
reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy