Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.xbean.finder;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.xbean.asm9.original.commons.EmptyVisitor;
import org.apache.xbean.finder.util.SingleLinkedList;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
/**
* @version $Rev: 1881759 $ $Date: 2020-09-16 10:29:43 +0200 (Wed, 16 Sep 2020) $
*/
public abstract class AbstractFinder implements IAnnotationFinder {
private final Map> annotated = new HashMap>();
protected final Map classInfos = new HashMap();
protected final Map originalInfos = new HashMap();
private final List classesNotLoaded = new ArrayList();
private final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES;
protected abstract URL getResource(String className);
protected abstract Class> loadClass(String fixedName) throws ClassNotFoundException;
public List getAnnotatedClassNames() {
return new ArrayList(originalInfos.keySet());
}
/**
* The link() method must be called to successfully use the findSubclasses and findImplementations methods
* @return
* @throws IOException
*/
public AbstractFinder link() throws IOException {
// already linked?
if (originalInfos.size() > 0) return this;
// keep track of what was originally from the archives
originalInfos.putAll(classInfos);
for (ClassInfo classInfo : classInfos.values().toArray(new ClassInfo[classInfos.size()])) {
linkParent(classInfo);
}
for (ClassInfo classInfo : classInfos.values().toArray(new ClassInfo[classInfos.size()])) {
linkInterfaces(classInfo);
}
return this;
}
private void linkParent(ClassInfo classInfo) throws IOException {
if (classInfo.superType == null) return;
if (classInfo.superType.equals("java.lang.Object")) return;
ClassInfo parentInfo = classInfo.superclassInfo;
if (parentInfo == null) {
parentInfo = classInfos.get(classInfo.superType);
if (parentInfo == null) {
if (classInfo.clazz != null) {
readClassDef(((Class>) classInfo.clazz).getSuperclass());
} else {
readClassDef(classInfo.superType);
}
parentInfo = classInfos.get(classInfo.superType);
if (parentInfo == null) return;
linkParent(parentInfo);
}
classInfo.superclassInfo = parentInfo;
}
if (!parentInfo.subclassInfos.contains(classInfo)) {
parentInfo.subclassInfos.add(classInfo);
}
}
private void linkInterfaces(ClassInfo classInfo) throws IOException {
final List infos = new ArrayList();
if (classInfo.clazz != null){
final Class>[] interfaces = classInfo.clazz.getInterfaces();
for (Class> clazz : interfaces) {
ClassInfo interfaceInfo = classInfos.get(clazz.getName());
if (interfaceInfo == null){
readClassDef(clazz);
}
interfaceInfo = classInfos.get(clazz.getName());
if (interfaceInfo != null) {
infos.add(interfaceInfo);
}
}
} else {
for (String className : classInfo.interfaces) {
ClassInfo interfaceInfo = classInfos.get(className);
if (interfaceInfo == null){
readClassDef(className);
}
interfaceInfo = classInfos.get(className);
if (interfaceInfo != null) {
infos.add(interfaceInfo);
}
}
}
for (ClassInfo info : infos) {
linkInterfaces(info);
}
}
public boolean isAnnotationPresent(Class extends Annotation> annotation) {
List infos = annotated.get(annotation.getName());
return infos != null && !infos.isEmpty();
}
/**
* Returns a list of classes that could not be loaded in last invoked findAnnotated* method.
*
* The list will only contain entries of classes whose byte code matched the requirements
* of last invoked find* method, but were unable to be loaded and included in the results.
*
* The list returned is unmodifiable. Once obtained, the returned list will be a live view of the
* results from the last findAnnotated* method call.
*
* This method is not thread safe.
* @return an unmodifiable live view of classes that could not be loaded in previous findAnnotated* call.
*/
public List getClassesNotLoaded() {
return Collections.unmodifiableList(classesNotLoaded);
}
public List findAnnotatedPackages(Class extends Annotation> annotation) {
classesNotLoaded.clear();
List packages = new ArrayList();
List infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof PackageInfo) {
PackageInfo packageInfo = (PackageInfo) info;
try {
Package pkg = packageInfo.get();
// double check via proper reflection
if (pkg.isAnnotationPresent(annotation)) {
packages.add(pkg);
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(packageInfo.getName());
}
}
}
return packages;
}
public List> findAnnotatedClasses(Class extends Annotation> annotation) {
classesNotLoaded.clear();
List> classes = new ArrayList>();
List infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof ClassInfo) {
ClassInfo classInfo = (ClassInfo) info;
try {
Class clazz = classInfo.get();
// double check via proper reflection
if (clazz.isAnnotationPresent(annotation)) {
classes.add(clazz);
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
}
}
}
return classes;
}
public List>> findMetaAnnotatedClasses(Class extends Annotation> annotation) {
List> classes = findAnnotatedClasses(annotation);
List>> list = new ArrayList>>();
for (final Class> clazz : classes) {
list.add(new MetaAnnotatedClass(clazz));
}
return list;
}
/**
* Naive implementation - works extremelly slow O(n^3)
*
* @param annotation
* @return list of directly or indirectly (inherited) annotated classes
*/
public List> findInheritedAnnotatedClasses(Class extends Annotation> annotation) {
classesNotLoaded.clear();
List> classes = new ArrayList>();
List infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
try {
if(info instanceof ClassInfo){
classes.add(((ClassInfo) info).get());
}
} catch (ClassNotFoundException cnfe) {
// TODO: ignored, but a log message would be appropriate
}
}
boolean annClassFound;
List tempClassInfos = new ArrayList(classInfos.values());
do {
annClassFound = false;
for (int pos = 0; pos < tempClassInfos.size(); pos++) {
ClassInfo classInfo = tempClassInfos.get(pos);
try {
// check whether any superclass is annotated
String superType = classInfo.getSuperType();
for (Class clazz : classes) {
if (superType.equals(clazz.getName())) {
classes.add(classInfo.get());
tempClassInfos.remove(pos);
annClassFound = true;
break;
}
}
// check whether any interface is annotated
List interfces = classInfo.getInterfaces();
for (String interfce: interfces) {
for (Class clazz : classes) {
if (interfce.replaceFirst("<.*>","").equals(clazz.getName())) {
classes.add(classInfo.get());
tempClassInfos.remove(pos);
annClassFound = true;
break;
}
}
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
} catch (NoClassDefFoundError e) {
classesNotLoaded.add(classInfo.getName());
}
}
} while (annClassFound);
return classes;
}
public List findAnnotatedMethods(Class extends Annotation> annotation) {
classesNotLoaded.clear();
List seen = new ArrayList();
List methods = new ArrayList();
List infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof MethodInfo && !info.getName().equals("")) {
MethodInfo methodInfo = (MethodInfo) info;
ClassInfo classInfo = methodInfo.getDeclaringClass();
if (seen.contains(classInfo)) continue;
seen.add(classInfo);
try {
Class clazz = classInfo.get();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(annotation)) {
methods.add(method);
}
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
}
}
}
return methods;
}
public List> findMetaAnnotatedMethods(Class extends Annotation> annotation) {
List methods = findAnnotatedMethods(annotation);
List> list = new ArrayList>();
for (final Method method : methods) {
list.add(new MetaAnnotatedMethod(method));
}
return list;
}
public List findAnnotatedConstructors(Class extends Annotation> annotation) {
classesNotLoaded.clear();
List seen = new ArrayList();
List constructors = new ArrayList();
List infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof MethodInfo && info.getName().equals("")) {
MethodInfo methodInfo = (MethodInfo) info;
ClassInfo classInfo = methodInfo.getDeclaringClass();
if (seen.contains(classInfo)) continue;
seen.add(classInfo);
try {
Class clazz = classInfo.get();
for (Constructor constructor : clazz.getConstructors()) {
if (constructor.isAnnotationPresent(annotation)) {
constructors.add(constructor);
}
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
}
}
}
return constructors;
}
public List findAnnotatedFields(Class extends Annotation> annotation) {
classesNotLoaded.clear();
List seen = new ArrayList();
List fields = new ArrayList();
List infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof FieldInfo) {
FieldInfo fieldInfo = (FieldInfo) info;
ClassInfo classInfo = fieldInfo.getDeclaringClass();
if (seen.contains(classInfo)) continue;
seen.add(classInfo);
try {
Class clazz = classInfo.get();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(annotation)) {
fields.add(field);
}
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
}
}
}
return fields;
}
public List> findMetaAnnotatedFields(Class extends Annotation> annotation) {
List fields = findAnnotatedFields(annotation);
List> list = new ArrayList>();
for (final Field field : fields) {
list.add(new MetaAnnotatedField(field));
}
return list;
}
public List> findClassesInPackage(String packageName, boolean recursive) {
classesNotLoaded.clear();
List> classes = new ArrayList>();
for (ClassInfo classInfo : classInfos.values()) {
try {
if (recursive && classInfo.getPackageName().startsWith(packageName)){
classes.add(classInfo.get());
} else if (classInfo.getPackageName().equals(packageName)){
classes.add(classInfo.get());
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
}
}
return classes;
}
public List> findSubclasses(Class clazz) {
if (clazz == null) throw new NullPointerException("class cannot be null");
classesNotLoaded.clear();
final ClassInfo classInfo = classInfos.get(clazz.getName());
List> found = new ArrayList>();
if (classInfo == null) return found;
findSubclasses(classInfo, found, clazz);
return found;
}
private void findSubclasses(ClassInfo classInfo, List> found, Class clazz) {
for (ClassInfo subclassInfo : classInfo.subclassInfos) {
try {
found.add(subclassInfo.get().asSubclass(clazz));
} catch (ClassNotFoundException e) {
classesNotLoaded.add(subclassInfo.getName());
}
findSubclasses(subclassInfo, found, clazz);
}
}
private List> _findSubclasses(Class clazz) {
if (clazz == null) throw new NullPointerException("class cannot be null");
List> classes = new ArrayList>();
for (ClassInfo classInfo : classInfos.values()) {
try {
if (clazz.getName().equals(classInfo.superType)) {
if (clazz.isAssignableFrom(classInfo.get())) {
classes.add(classInfo.get().asSubclass(clazz));
classes.addAll(_findSubclasses(classInfo.get().asSubclass(clazz)));
}
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(classInfo.getName());
}
}
return classes;
}
public List> findImplementations(Class clazz) {
if (clazz == null) throw new NullPointerException("class cannot be null");
if (!clazz.isInterface()) new IllegalArgumentException("class must be an interface");
classesNotLoaded.clear();
final String interfaceName = clazz.getName();
// Collect all interfaces extending the main interface (recursively)
// Collect all implementations of interfaces
// i.e. all *directly* implementing classes
List infos = collectImplementations(interfaceName);
// Collect all subclasses of implementations
List> classes = new ArrayList>();
for (ClassInfo info : infos) {
try {
final Class extends T> impl = (Class extends T>) info.get();
if (clazz.isAssignableFrom(impl)) {
classes.add(impl);
// Optimization: Don't need to call this method if parent class was already searched
classes.addAll(_findSubclasses(impl));
}
} catch (ClassNotFoundException e) {
classesNotLoaded.add(info.getName());
}
}
return classes;
}
private List collectImplementations(String interfaceName) {
final List infos = new ArrayList();
for (ClassInfo classInfo : classInfos.values()) {
if (classInfo.interfaces.contains(interfaceName)) {
infos.add(classInfo);
try {
final Class clazz = classInfo.get();
if (clazz.isInterface() && !clazz.isAnnotation()) {
infos.addAll(collectImplementations(classInfo.name));
}
} catch (ClassNotFoundException ignore) {
// we'll deal with this later
}
}
}
return infos;
}
protected List getAnnotationInfos(String name) {
List infos = annotated.get(name);
if (infos == null) {
infos = new SingleLinkedList();
annotated.put(name, infos);
}
return infos;
}
protected void readClassDef(String className) {
int pos = className.indexOf("<");
if (pos > -1) {
className = className.substring(0, pos);
}
pos = className.indexOf(">");
if (pos > -1) {
className = className.substring(0, pos);
}
if (!className.endsWith(".class")) {
className = className.replace('.', '/') + ".class";
}
try {
// TODO: check out META-INF/versions//className
URL resource = getResource(className);
if (resource != null) {
InputStream in = resource.openStream();
try {
readClassDef(in);
} finally {
in.close();
}
} else {
classesNotLoaded.add(className + " (no resource found for class)");
}
} catch (IOException e) {
classesNotLoaded.add(className + e.getMessage());
}
}
protected void readClassDef(InputStream in) throws IOException {
readClassDef(in, null);
}
protected void readClassDef(InputStream in, String path) throws IOException {
ClassReader classReader = new ClassReader(in);
classReader.accept(new InfoBuildingVisitor(path), ASM_FLAGS);
}
protected void readClassDef(Class clazz) {
List infos = new ArrayList();
Package aPackage = clazz.getPackage();
if (aPackage != null){
final PackageInfo info = new PackageInfo(aPackage);
for (AnnotationInfo annotation : info.getAnnotations()) {
List annotationInfos = getAnnotationInfos(annotation.getName());
if (!annotationInfos.contains(info)) {
annotationInfos.add(info);
}
}
}
ClassInfo classInfo = new ClassInfo(clazz);
infos.add(classInfo);
classInfos.put(clazz.getName(), classInfo);
for (Method method : clazz.getDeclaredMethods()) {
infos.add(new MethodInfo(classInfo, method));
}
for (Constructor constructor : clazz.getConstructors()) {
infos.add(new MethodInfo(classInfo, constructor));
}
for (Field field : clazz.getDeclaredFields()) {
infos.add(new FieldInfo(classInfo, field));
}
for (Info info : infos) {
for (AnnotationInfo annotation : info.getAnnotations()) {
List annotationInfos = getAnnotationInfos(annotation.getName());
annotationInfos.add(info);
}
}
}
public class Annotatable {
private final List annotations = new ArrayList();
public Annotatable(AnnotatedElement element) {
for (Annotation annotation : getAnnotations(element)) {
annotations.add(new AnnotationInfo(annotation.annotationType().getName()));
}
}
public Annotatable() {
}
public List getAnnotations() {
return annotations;
}
/**
* Utility method to get around some errors caused by
* interactions between the Equinox class loaders and
* the OpenJPA transformation process. There is a window
* where the OpenJPA transformation process can cause
* an annotation being processed to get defined in a
* classloader during the actual defineClass call for
* that very class (e.g., recursively). This results in
* a LinkageError exception. If we see one of these,
* retry the request. Since the annotation will be
* defined on the second pass, this should succeed. If
* we get a second exception, then it's likely some
* other problem.
*
* @param element The AnnotatedElement we need information for.
*
* @return An array of the Annotations defined on the element.
*/
private Annotation[] getAnnotations(AnnotatedElement element) {
try {
return element.getAnnotations();
} catch (LinkageError e) {
return element.getAnnotations();
}
}
}
public static interface Info {
String getName();
List getAnnotations();
}
public class PackageInfo extends Annotatable implements Info {
private final String name;
private final ClassInfo info;
private final Package pkg;
public PackageInfo(Package pkg){
super(pkg);
this.pkg = pkg;
this.name = pkg.getName();
this.info = null;
}
public PackageInfo(String name) {
info = new ClassInfo(name, null);
this.name = name;
this.pkg = null;
}
public String getName() {
return name;
}
public Package get() throws ClassNotFoundException {
return (pkg != null)?pkg:info.get().getPackage();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PackageInfo that = (PackageInfo) o;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return true;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}
public class ClassInfo extends Annotatable implements Info {
private String name;
private final List methods = new SingleLinkedList();
private final List constructors = new SingleLinkedList();
private String superType;
private ClassInfo superclassInfo;
private final List subclassInfos = new SingleLinkedList();
private final List interfaces = new SingleLinkedList();
private final List fields = new SingleLinkedList();
//e.g. bundle class path prefix.
private String path;
private Class> clazz;
public ClassInfo(Class clazz) {
super(clazz);
this.clazz = clazz;
this.name = clazz.getName();
Class superclass = clazz.getSuperclass();
this.superType = superclass != null ? superclass.getName(): null;
for (Class intrface : clazz.getInterfaces()) {
this.interfaces.add(intrface.getName());
}
}
public ClassInfo(String name, String superType) {
this.name = name;
this.superType = superType;
}
public String getPackageName(){
return name.indexOf(".") > 0 ? name.substring(0, name.lastIndexOf(".")) : "" ;
}
public List getConstructors() {
return constructors;
}
public List getInterfaces() {
return interfaces;
}
public List getFields() {
return fields;
}
public List getMethods() {
return methods;
}
public String getName() {
return name;
}
public String getSuperType() {
return superType;
}
public Class> get() throws ClassNotFoundException {
if (clazz != null) return clazz;
try {
String fixedName = name.replaceFirst("<.*>", "");
this.clazz = loadClass(fixedName);
return clazz;
} catch (ClassNotFoundException notFound) {
classesNotLoaded.add(name);
throw notFound;
}
}
public String toString() {
return name;
}
public String getPath() {
return path;
}
}
public class MethodInfo extends Annotatable implements Info {
private final ClassInfo declaringClass;
private final String returnType;
private final String name;
private final List> parameterAnnotations = new ArrayList>();
public MethodInfo(ClassInfo info, Constructor constructor){
super(constructor);
this.declaringClass = info;
this.name = "";
this.returnType = Void.TYPE.getName();
}
public MethodInfo(ClassInfo info, Method method){
super(method);
this.declaringClass = info;
this.name = method.getName();
this.returnType = method.getReturnType().getName();
}
public MethodInfo(ClassInfo declarignClass, String name, String returnType) {
this.declaringClass = declarignClass;
this.name = name;
this.returnType = returnType;
}
public List> getParameterAnnotations() {
return parameterAnnotations;
}
public List getParameterAnnotations(int index) {
if (index >= parameterAnnotations.size()) {
for (int i = parameterAnnotations.size(); i <= index; i++) {
List annotationInfos = new ArrayList();
parameterAnnotations.add(i, annotationInfos);
}
}
return parameterAnnotations.get(index);
}
public String getName() {
return name;
}
public ClassInfo getDeclaringClass() {
return declaringClass;
}
public String getReturnType() {
return returnType;
}
public String toString() {
return declaringClass + "@" + name;
}
}
public class FieldInfo extends Annotatable implements Info {
private final String name;
private final String type;
private final ClassInfo declaringClass;
public FieldInfo(ClassInfo info, Field field){
super(field);
this.declaringClass = info;
this.name = field.getName();
this.type = field.getType().getName();
}
public FieldInfo(ClassInfo declaringClass, String name, String type) {
this.declaringClass = declaringClass;
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public ClassInfo getDeclaringClass() {
return declaringClass;
}
public String getType() {
return type;
}
public String toString() {
return declaringClass + "#" + name;
}
}
public class AnnotationInfo extends Annotatable implements Info {
private final String name;
public AnnotationInfo(Annotation annotation){
this(annotation.getClass().getName());
}
public AnnotationInfo(Class extends Annotation> annotation) {
this.name = annotation.getName().intern();
}
public AnnotationInfo(String name) {
name = name.replaceAll("^L|;$", "");
name = name.replace('/', '.');
this.name = name.intern();
}
public String getName() {
return name;
}
public String toString() {
return name;
}
}
public class InfoBuildingVisitor extends EmptyVisitor {
private Info info;
private String path;
public InfoBuildingVisitor(String path) {
this.path = path;
}
public InfoBuildingVisitor(Info info) {
this.info = info;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (name.endsWith("package-info")) {
info = new PackageInfo(javaName(name));
} else {
ClassInfo classInfo = new ClassInfo(javaName(name), javaName(superName));
classInfo.path = path;
// if (signature == null) {
for (String interfce : interfaces) {
classInfo.getInterfaces().add(javaName(interfce));
}
// } else {
// // the class uses generics
// new SignatureReader(signature).accept(new GenericAwareInfoBuildingVisitor(GenericAwareInfoBuildingVisitor.TYPE.CLASS, classInfo));
// }
info = classInfo;
classInfos.put(classInfo.getName(), classInfo);
}
}
private String javaName(String name) {
return (name == null)? null:name.replace('/', '.');
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationInfo annotationInfo = new AnnotationInfo(desc);
info.getAnnotations().add(annotationInfo);
getAnnotationInfos(annotationInfo.getName()).add(info);
return new InfoBuildingVisitor(annotationInfo).annotationVisitor();
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
ClassInfo classInfo = ((ClassInfo) info);
FieldInfo fieldInfo = new FieldInfo(classInfo, name, desc);
classInfo.getFields().add(fieldInfo);
return new InfoBuildingVisitor(fieldInfo).fieldVisitor();
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
ClassInfo classInfo = ((ClassInfo) info);
MethodInfo methodInfo = new MethodInfo(classInfo, name, desc);
classInfo.getMethods().add(methodInfo);
return new InfoBuildingVisitor(methodInfo).methodVisitor();
}
@Override
public AnnotationVisitor visitMethodParameterAnnotation(int param, String desc, boolean visible) {
MethodInfo methodInfo = ((MethodInfo) info);
List annotationInfos = methodInfo.getParameterAnnotations(param);
AnnotationInfo annotationInfo = new AnnotationInfo(desc);
annotationInfos.add(annotationInfo);
return new InfoBuildingVisitor(annotationInfo).annotationVisitor();
}
}
}