package org.yajul.micro;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yajul.scanner.AbstractScanner;
import org.yajul.util.ReflectionUtil;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;
/**
* Finds classes with a given set of annotations.
* <br>User: Josh
* Date: Sep 24, 2008
* Time: 6:22:36 AM
*/
public abstract class AbstractAnnotationScanner extends AbstractScanner {
private static final Logger log = LoggerFactory.getLogger(AbstractAnnotationScanner.class);
private Set<Class<? extends Annotation>> annotations = new HashSet<Class<? extends Annotation>>();
public AbstractAnnotationScanner(String resourceName) {
super(resourceName);
}
public AbstractAnnotationScanner(String resourceName, ClassLoader classLoader) {
super(resourceName, classLoader);
}
public void addAnnotation(Class<? extends Annotation> annotation) {
annotations.add(annotation);
}
@Override
final public void handleItem(String name) {
if (name.endsWith(".class")) {
String className = ReflectionUtil.filenameToClassname(name);
try {
// Use Javassist to get the meta data so we don't actually
// load the class into the class loader.
ClassFile classFile = getClassFile(name);
for (Class<? extends Annotation> annotation : annotations) {
if (hasAnnotation(classFile, annotation)) {
handleAnnotation(name, classFile, annotation);
}
}
} catch (IOException e) {
if (log.isDebugEnabled())
log.debug("handleItem() " + e.getMessage());
}
}
}
protected abstract void handleAnnotation(String name, ClassFile classFile, Class<? extends Annotation> annotation);
protected ClassFile getClassFile(String name) throws IOException {
InputStream stream = getResourceAsStream(name);
DataInputStream dstream = new DataInputStream(stream);
try {
return new ClassFile(dstream);
}
finally {
dstream.close();
stream.close();
}
}
/**
* @param classFile the ClassFile
* @param annotationType the annotation
* @return true if the Javassist {@link ClassFile} has the specfied annotation
*/
protected boolean hasAnnotation(ClassFile classFile, Class<? extends Annotation> annotationType) {
AnnotationsAttribute visible = (AnnotationsAttribute) classFile.getAttribute(AnnotationsAttribute.visibleTag);
return visible != null && visible.getAnnotation(annotationType.getName()) != null;
}
}