WW-5207 Uses ASM 9 by default

This commit is contained in:
Lukasz Lenart
2022-08-08 17:00:42 +02:00
parent 3c9465b857
commit 86b45e96fc
2 changed files with 80 additions and 145 deletions
@@ -29,11 +29,11 @@ import java.util.List;
/**
* ClassFinder searches the classpath of the specified ClassLoaderInterface for
* packages, classes, constructors, methods, or fields with specific annotations.
*
* <p>
* For security reasons ASM is used to find the annotations. Classes are not
* loaded unless they match the requirements of a called findAnnotated* method.
* Once loaded, these classes are cached.
*
* <p>
* The getClassesNotLoaded() method can be used immediately after any find*
* method to get a list of classes which matched the find requirements (i.e.
* contained the annotation), but were unable to be loaded.
@@ -67,32 +67,32 @@ public interface ClassFinder {
List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation);
List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation);
List<Class<?>> findAnnotatedClasses(Class<? extends Annotation> annotation);
List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation);
List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation);
List<Constructor<?>> findAnnotatedConstructors(Class<? extends Annotation> annotation);
List<Field> findAnnotatedFields(Class<? extends Annotation> annotation);
List<Class> findClassesInPackage(String packageName, boolean recursive);
List<Class<?>> findClassesInPackage(String packageName, boolean recursive);
List<Class> findClasses(Test<ClassInfo> test);
List<Class<?>> findClasses(Test<ClassInfo> test);
List<Class> findClasses();
List<Class<?>> findClasses();
ClassLoaderInterface getClassLoaderInterface();
public static interface Info {
interface Info {
String getName();
List<AnnotationInfo> getAnnotations();
}
public class AnnotationInfo extends Annotatable implements Info {
class AnnotationInfo extends Annotatable implements Info {
private final String name;
public AnnotationInfo(Annotation annotation){
public AnnotationInfo(Annotation annotation) {
this(annotation.getClass().getName());
}
@@ -116,7 +116,7 @@ public interface ClassFinder {
}
}
public class Annotatable {
class Annotatable {
private final List<AnnotationInfo> annotations = new ArrayList<>();
public Annotatable(AnnotatedElement element) {
@@ -134,12 +134,12 @@ public interface ClassFinder {
}
public class PackageInfo extends Annotatable implements Info {
class PackageInfo extends Annotatable implements Info {
private final String name;
private final ClassInfo info;
private final Package pkg;
public PackageInfo(Package pkg){
public PackageInfo(Package pkg) {
super(pkg);
this.pkg = pkg;
this.name = pkg.getName();
@@ -157,11 +157,11 @@ public interface ClassFinder {
}
public Package get() throws ClassNotFoundException {
return (pkg != null)?pkg:info.get().getPackage();
return (pkg != null) ? pkg : info.get().getPackage();
}
}
public class ClassInfo extends Annotatable implements Info {
class ClassInfo extends Annotatable implements Info {
private final String name;
private final List<MethodInfo> methods = new ArrayList<>();
private final List<MethodInfo> constructors = new ArrayList<>();
@@ -169,17 +169,18 @@ public interface ClassFinder {
private final List<String> interfaces = new ArrayList<>();
private final List<String> superInterfaces = new ArrayList<>();
private final List<FieldInfo> fields = new ArrayList<>();
private final ClassFinder classFinder;
private Class<?> clazz;
private ClassFinder classFinder;
private ClassNotFoundException notFound;
public ClassInfo(Class clazz, ClassFinder classFinder) {
public ClassInfo(Class<?> clazz, ClassFinder classFinder) {
super(clazz);
this.clazz = clazz;
this.classFinder = classFinder;
this.name = clazz.getName();
Class superclass = clazz.getSuperclass();
this.superType = superclass != null ? superclass.getName(): null;
Class<?> superclass = clazz.getSuperclass();
this.superType = superclass != null ? superclass.getName() : null;
}
public ClassInfo(String name, String superType, ClassFinder classFinder) {
@@ -188,8 +189,8 @@ public interface ClassFinder {
this.classFinder = classFinder;
}
public String getPackageName(){
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "" ;
public String getPackageName() {
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "";
}
public List<MethodInfo> getConstructors() {
@@ -220,7 +221,7 @@ public interface ClassFinder {
return superType;
}
public Class get() throws ClassNotFoundException {
public Class<?> get() throws ClassNotFoundException {
if (clazz != null) return clazz;
if (notFound != null) throw notFound;
try {
@@ -239,20 +240,20 @@ public interface ClassFinder {
}
}
public class MethodInfo extends Annotatable implements Info {
class MethodInfo extends Annotatable implements Info {
private final ClassInfo declaringClass;
private final String returnType;
private final String name;
private final List<List<AnnotationInfo>> parameterAnnotations = new ArrayList<>();
public MethodInfo(ClassInfo info, Constructor constructor){
public MethodInfo(ClassInfo info, Constructor<?> constructor) {
super(constructor);
this.declaringClass = info;
this.name = "<init>";
this.returnType = Void.TYPE.getName();
}
public MethodInfo(ClassInfo info, Method method){
public MethodInfo(ClassInfo info, Method method) {
super(method);
this.declaringClass = info;
this.name = method.getName();
@@ -297,12 +298,12 @@ public interface ClassFinder {
}
}
public class FieldInfo extends Annotatable implements Info {
class FieldInfo extends Annotatable implements Info {
private final String name;
private final String type;
private final ClassInfo declaringClass;
public FieldInfo(ClassInfo info, Field field){
public FieldInfo(ClassInfo info, Field field) {
super(field);
this.declaringClass = info;
this.name = field.getName();
@@ -38,6 +38,7 @@ import org.objectweb.asm.Opcodes;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -45,7 +46,15 @@ import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
@@ -57,9 +66,9 @@ public class DefaultClassFinder implements ClassFinder {
private final List<String> classesNotLoaded = new ArrayList<>();
private boolean extractBaseInterfaces;
private ClassLoaderInterface classLoaderInterface;
private FileManager fileManager;
private final ClassLoaderInterface classLoaderInterface;
private final boolean extractBaseInterfaces;
private final FileManager fileManager;
public DefaultClassFinder(ClassLoaderInterface classLoaderInterface, Collection<URL> urls, boolean extractBaseInterfaces, Set<String> protocols, Test<String> classNameFilter) {
this.classLoaderInterface = classLoaderInterface;
@@ -97,46 +106,6 @@ public class DefaultClassFinder implements ClassFinder {
}
}
public DefaultClassFinder(Class... classes){
this(Arrays.asList(classes));
}
public DefaultClassFinder(List<Class> classes){
this.classLoaderInterface = null;
List<Info> infos = new ArrayList<>();
List<Package> packages = new ArrayList<>();
for (Class clazz : classes) {
Package aPackage = clazz.getPackage();
if (aPackage != null && !packages.contains(aPackage)){
infos.add(new PackageInfo(aPackage));
packages.add(aPackage);
}
ClassInfo classInfo = new ClassInfo(clazz, this);
infos.add(classInfo);
classInfos.put(classInfo.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<Info> annotationInfos = getAnnotationInfos(annotation.getName());
annotationInfos.add(info);
}
}
}
public ClassLoaderInterface getClassLoaderInterface() {
return classLoaderInterface;
}
@@ -171,15 +140,15 @@ public class DefaultClassFinder implements ClassFinder {
return packages;
}
public List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation) {
public List<Class<?>> findAnnotatedClasses(Class<? extends Annotation> annotation) {
classesNotLoaded.clear();
List<Class> classes = new ArrayList<>();
List<Class<?>> classes = new ArrayList<>();
List<Info> infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof ClassInfo) {
ClassInfo classInfo = (ClassInfo) info;
try {
Class clazz = classInfo.get();
Class<?> clazz = classInfo.get();
// double check via proper reflection
if (clazz.isAnnotationPresent(annotation)) {
classes.add(clazz);
@@ -208,7 +177,7 @@ public class DefaultClassFinder implements ClassFinder {
seen.add(classInfo);
try {
Class clazz = classInfo.get();
Class<?> clazz = classInfo.get();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(annotation)) {
methods.add(method);
@@ -223,10 +192,10 @@ public class DefaultClassFinder implements ClassFinder {
return methods;
}
public List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
public List<Constructor<?>> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
classesNotLoaded.clear();
List<ClassInfo> seen = new ArrayList<>();
List<Constructor> constructors = new ArrayList<>();
List<Constructor<?>> constructors = new ArrayList<>();
List<Info> infos = getAnnotationInfos(annotation.getName());
for (Info info : infos) {
if (info instanceof MethodInfo && "<init>".equals(info.getName())) {
@@ -238,8 +207,8 @@ public class DefaultClassFinder implements ClassFinder {
seen.add(classInfo);
try {
Class clazz = classInfo.get();
for (Constructor constructor : clazz.getConstructors()) {
Class<?> clazz = classInfo.get();
for (Constructor<?> constructor : clazz.getConstructors()) {
if (constructor.isAnnotationPresent(annotation)) {
constructors.add(constructor);
}
@@ -270,7 +239,7 @@ public class DefaultClassFinder implements ClassFinder {
seen.add(classInfo);
try {
Class clazz = classInfo.get();
Class<?> clazz = classInfo.get();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(annotation)) {
fields.add(field);
@@ -285,14 +254,14 @@ public class DefaultClassFinder implements ClassFinder {
return fields;
}
public List<Class> findClassesInPackage(String packageName, boolean recursive) {
public List<Class<?>> findClassesInPackage(String packageName, boolean recursive) {
classesNotLoaded.clear();
List<Class> classes = new ArrayList<>();
List<Class<?>> classes = new ArrayList<>();
for (ClassInfo classInfo : classInfos.values()) {
try {
if (recursive && classInfo.getPackageName().startsWith(packageName)){
if (recursive && classInfo.getPackageName().startsWith(packageName)) {
classes.add(classInfo.get());
} else if (classInfo.getPackageName().equals(packageName)){
} else if (classInfo.getPackageName().equals(packageName)) {
classes.add(classInfo.get());
}
} catch (Throwable e) {
@@ -303,9 +272,9 @@ public class DefaultClassFinder implements ClassFinder {
return classes;
}
public List<Class> findClasses(Test<ClassInfo> test) {
public List<Class<?>> findClasses(Test<ClassInfo> test) {
classesNotLoaded.clear();
List<Class> classes = new ArrayList<>();
List<Class<?>> classes = new ArrayList<>();
for (ClassInfo classInfo : classInfos.values()) {
try {
if (test.test(classInfo)) {
@@ -319,9 +288,9 @@ public class DefaultClassFinder implements ClassFinder {
return classes;
}
public List<Class> findClasses() {
public List<Class<?>> findClasses() {
classesNotLoaded.clear();
List<Class> classes = new ArrayList<>();
List<Class<?>> classes = new ArrayList<>();
for (ClassInfo classInfo : classInfos.values()) {
try {
classes.add(classInfo.get());
@@ -333,9 +302,9 @@ public class DefaultClassFinder implements ClassFinder {
return classes;
}
private List<String> file(URL location) {
private List<String> file(URL location) throws UnsupportedEncodingException {
List<String> classNames = new ArrayList<>();
File dir = new File(URLDecoder.decode(location.getPath()));
File dir = new File(URLDecoder.decode(location.getPath(), "UTF-8"));
if ("META-INF".equals(dir.getName())) {
dir = dir.getParentFile(); // Scrape "META-INF" off
}
@@ -347,15 +316,17 @@ public class DefaultClassFinder implements ClassFinder {
private void scanDir(File dir, List<String> classNames, String packageName) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
scanDir(file, classNames, packageName + file.getName() + ".");
} else if (file.getName().endsWith(".class")) {
String name = file.getName();
name = name.replaceFirst(".class$", "");
// Classes packaged in an exploded .war (e.g. in a VFS file system) should not
// have WEB-INF.classes in their package name.
classNames.add(StringUtils.removeStart(packageName, "WEB-INF.classes.") + name);
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
scanDir(file, classNames, packageName + file.getName() + ".");
} else if (file.getName().endsWith(".class")) {
String name = file.getName();
name = name.replaceFirst(".class$", "");
// Classes packaged in an exploded .war (e.g. in a VFS file system) should not
// have WEB-INF.classes in their package name.
classNames.add(StringUtils.removeStart(packageName, "WEB-INF.classes.") + name);
}
}
}
}
@@ -363,12 +334,9 @@ public class DefaultClassFinder implements ClassFinder {
private List<String> jar(URL location) throws IOException {
URL url = fileManager.normalizeToFileProtocol(location);
if (url != null) {
InputStream in = url.openStream();
try {
try (InputStream in = url.openStream()) {
JarInputStream jarStream = new JarInputStream(in);
return jar(jarStream);
} finally {
in.close();
}
} else {
LOG.debug("Unable to read [{}]", location.toExternalForm());
@@ -388,7 +356,7 @@ public class DefaultClassFinder implements ClassFinder {
className = className.replaceFirst(".class$", "");
//war files are treated as .jar files, so takeout WEB-INF/classes
className = StringUtils.removeStart(className, "WEB-INF/classes/");
className = StringUtils.removeStart(className, "WEB-INF/classes/");
className = className.replace('/', '.');
classNames.add(className);
@@ -397,40 +365,8 @@ public class DefaultClassFinder implements ClassFinder {
return classNames;
}
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, ClassFinder classFinder) {
info = new ClassInfo(name, null, classFinder);
this.name = name;
this.pkg = null;
}
public String getName() {
return name;
}
public Package get() throws ClassNotFoundException {
return (pkg != null)?pkg:info.get().getPackage();
}
}
private List<Info> getAnnotationInfos(String name) {
List<Info> infos = annotated.get(name);
if (infos == null) {
infos = new ArrayList<>();
annotated.put(name, infos);
}
return infos;
return annotated.computeIfAbsent(name, k -> new ArrayList<>());
}
private void readClassDef(String className) {
@@ -454,19 +390,16 @@ public class DefaultClassFinder implements ClassFinder {
}
public class InfoBuildingVisitor extends ClassVisitor {
private final ClassFinder classFinder;
private Info info;
private ClassFinder classFinder;
public InfoBuildingVisitor(ClassFinder classFinder) {
super(Opcodes.ASM7);
super(Opcodes.ASM9);
this.classFinder = classFinder;
}
public InfoBuildingVisitor(Info info, ClassFinder classFinder) {
this(classFinder);
this.info = info;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (name.endsWith("package-info")) {
@@ -480,8 +413,9 @@ public class DefaultClassFinder implements ClassFinder {
info = classInfo;
classInfos.put(classInfo.getName(), classInfo);
if (extractBaseInterfaces)
if (extractBaseInterfaces) {
extractSuperInterfaces(classInfo);
}
}
}