org.eclipse.jetty.annotations.AnnotationParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testatoo-container-jetty-full Show documentation
Show all versions of testatoo-container-jetty-full Show documentation
Testatoo Jetty Container with JSP support
// ========================================================================
// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.annotations;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.JarScanner;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.EmptyVisitor;
/**
* AnnotationParser
*
* Use asm to scan classes for annotations. A SAX-style parsing is done, with
* a handler being able to be registered to handle each annotation type.
*/
public class AnnotationParser
{
protected List _parsedClassNames = new ArrayList();
protected Map> _annotationHandlers = new HashMap>();
protected List _classHandlers = new ArrayList();
protected List _methodHandlers = new ArrayList();
protected List _fieldHandlers = new ArrayList();
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());
return name.replace('/', '.');
}
public abstract class Value
{
String _name;
public Value (String name)
{
_name = name;
}
public String getName()
{
return _name;
}
public abstract Object getValue();
}
public class SimpleValue extends Value
{
Object _val;
public SimpleValue(String name)
{
super(name);
}
public void setValue(Object val)
{
_val=val;
}
public Object getValue()
{
return _val;
}
public String toString()
{
return "("+getName()+":"+_val+")";
}
}
public class ListValue extends Value
{
List _val;
public ListValue (String name)
{
super(name);
_val = new ArrayList();
}
public Object getValue()
{
return _val;
}
public List getList()
{
return _val;
}
public void addValue (Value v)
{
_val.add(v);
}
public int size ()
{
return _val.size();
}
public String toString()
{
StringBuffer buff = new StringBuffer();
buff.append("(");
buff.append(getName());
buff.append(":");
for (Value n: _val)
{
buff.append(" "+n.toString());
}
buff.append(")");
return buff.toString();
}
}
public interface DiscoverableAnnotationHandler
{
public void handleClass (String className, int version, int access,
String signature, String superName, String[] interfaces,
String annotation, Listvalues);
public void handleMethod (String className, String methodName, int access,
String desc, String signature,String[] exceptions,
String annotation, Listvalues);
public void handleField (String className, String fieldName, int access,
String fieldType, String signature, Object value,
String annotation, Listvalues);
}
public interface ClassHandler
{
public void handle (String className, int version, int access, String signature, String superName, String[] interfaces);
}
public interface MethodHandler
{
public void handle (String className, String methodName, int access, String desc, String signature,String[] exceptions);
}
public interface FieldHandler
{
public void handle (String className, String fieldName, int access, String fieldType, String signature, Object value);
}
public class MyAnnotationVisitor implements AnnotationVisitor
{
List _annotationValues;
String _annotationName;
public MyAnnotationVisitor (String annotationName, List values)
{
_annotationValues = values;
_annotationName = annotationName;
}
public List getAnnotationValues()
{
return _annotationValues;
}
/**
* Visit a single-valued (name,value) pair for this annotation
* @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
*/
public void visit(String aname, Object avalue)
{
SimpleValue v = new SimpleValue(aname);
v.setValue(avalue);
_annotationValues.add(v);
}
/**
* Visit a (name,value) pair whose value is another Annotation
* @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
*/
public AnnotationVisitor visitAnnotation(String name, String desc)
{
String s = normalize(desc);
ListValue v = new ListValue(s);
_annotationValues.add(v);
MyAnnotationVisitor visitor = new MyAnnotationVisitor(s, v.getList());
return visitor;
}
/**
* Visit an array valued (name, value) pair for this annotation
* @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
*/
public AnnotationVisitor visitArray(String name)
{
ListValue v = new ListValue(name);
_annotationValues.add(v);
MyAnnotationVisitor visitor = new MyAnnotationVisitor(null, v.getList());
return visitor;
}
/**
* Visit a enum-valued (name,value) pair for this annotation
* @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)
*/
public void visitEnum(String name, String desc, String value)
{
//TODO
}
public void visitEnd()
{
}
}
/**
* MyClassVisitor
*
* ASM visitor for a class.
*/
public class MyClassVisitor extends EmptyVisitor
{
String _className;
int _access;
String _signature;
String _superName;
String[] _interfaces;
int _version;
public void visit (int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
_className = normalize(name);
_access = access;
_signature = signature;
_superName = superName;
_interfaces = interfaces;
_version = version;
_parsedClassNames.add(_className);
//call all registered ClassHandlers
String[] normalizedInterfaces = null;
if (interfaces!= null)
{
normalizedInterfaces = new String[interfaces.length];
int i=0;
for (String s : interfaces)
normalizedInterfaces[i++] = normalize(s);
}
for (ClassHandler h : AnnotationParser.this._classHandlers)
{
h.handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
}
}
public AnnotationVisitor visitAnnotation (String desc, boolean visible)
{
MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList())
{
public void visitEnd()
{
super.visitEnd();
//call all AnnotationHandlers with classname, annotation name + values
List handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handlers != null)
{
for (DiscoverableAnnotationHandler h:handlers)
{
h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
}
}
}
};
return visitor;
}
public MethodVisitor visitMethod (final int access,
final String name,
final String methodDesc,
final String signature,
final String[] exceptions)
{
return new EmptyVisitor ()
{
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
{
MyAnnotationVisitor visitor = new MyAnnotationVisitor (normalize(desc), new ArrayList())
{
public void visitEnd()
{
super.visitEnd();
//call all AnnotationHandlers with classname, method, annotation name + values
List handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handlers != null)
{
for (DiscoverableAnnotationHandler h:handlers)
{
h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
}
}
}
};
return visitor;
}
};
}
public FieldVisitor visitField (final int access,
final String fieldName,
final String fieldType,
final String signature,
final Object value)
{
return new EmptyVisitor ()
{
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
{
MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList())
{
public void visitEnd()
{
super.visitEnd();
List handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
if (handlers != null)
{
for (DiscoverableAnnotationHandler h:handlers)
{
h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
}
}
}
};
return visitor;
}
};
}
}
/**
* Register a handler that will be called back when the named annotation is
* encountered on a class.
*
* @param annotationName
* @param handler
*/
public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
{
List handlers = _annotationHandlers.get(annotationName);
if (handlers == null)
{
handlers = new ArrayList();
_annotationHandlers.put(annotationName, handlers);
}
handlers.add(handler);
}
public List getAnnotationHandlers(String annotationName)
{
List handlers = _annotationHandlers.get(annotationName);
if (handlers == null)
return Collections.emptyList();
return new ArrayList();
}
public List getAnnotationHandlers()
{
List allHandlers = new ArrayList();
for (List list:_annotationHandlers.values())
allHandlers.addAll(list);
return allHandlers;
}
public void registerClassHandler (ClassHandler handler)
{
_classHandlers.add(handler);
}
public boolean isParsed (String className)
{
return _parsedClassNames.contains(className);
}
public void parse (String className, ClassNameResolver resolver)
throws Exception
{
if (className == null)
return;
if (!resolver.isExcluded(className))
{
if (!isParsed(className) || resolver.shouldOverride(className))
{
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(this.getClass(), className, false);
if (resource!= null)
scanClass(resource.openStream());
}
}
}
public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
throws Exception
{
Class cz = clazz;
while (cz != null)
{
if (!resolver.isExcluded(cz.getName()))
{
if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
{
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(this.getClass(), nameAsResource, false);
if (resource!= null)
scanClass(resource.openStream());
}
}
if (visitSuperClasses)
cz = cz.getSuperclass();
else
cz = null;
}
}
public void parse (String[] classNames, ClassNameResolver resolver)
throws Exception
{
if (classNames == null)
return;
parse(Arrays.asList(classNames), resolver);
}
public void parse (List classNames, ClassNameResolver resolver)
throws Exception
{
for (String s:classNames)
{
if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
{
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(this.getClass(), s, false);
if (resource!= null)
scanClass(resource.openStream());
}
}
}
public void parse (Resource dir, ClassNameResolver resolver)
throws Exception
{
if (!dir.isDirectory() || !dir.exists())
return;
String[] files=dir.list();
for (int f=0;files!=null && f