2018-12-06 05:29:34 +03:00
|
|
|
|
package ru.gravit.launchserver.asm;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.jar.JarFile;
|
|
|
|
|
|
2018-12-26 15:33:49 +03:00
|
|
|
|
import org.objectweb.asm.ClassReader;
|
|
|
|
|
import org.objectweb.asm.ClassVisitor;
|
|
|
|
|
import org.objectweb.asm.Opcodes;
|
|
|
|
|
|
|
|
|
|
import ru.gravit.utils.helper.IOHelper;
|
|
|
|
|
|
2018-12-06 05:29:34 +03:00
|
|
|
|
/**
|
|
|
|
|
* Позволяет искать методы внутри незагруженных классов и общие суперклассы для
|
|
|
|
|
* чего угодно. Работает через поиск class-файлов в classpath.
|
|
|
|
|
*/
|
|
|
|
|
public class ClassMetadataReader {
|
2018-12-20 18:45:01 +03:00
|
|
|
|
private class CheckSuperClassVisitor extends ClassVisitor {
|
|
|
|
|
|
|
|
|
|
String superClassName;
|
|
|
|
|
|
|
|
|
|
public CheckSuperClassVisitor() {
|
|
|
|
|
super(Opcodes.ASM5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void visit(int version, int access, String name, String signature, String superName,
|
|
|
|
|
String[] interfaces) {
|
|
|
|
|
superClassName = superName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private final List<JarFile> cp;
|
|
|
|
|
|
|
|
|
|
public ClassMetadataReader(List<JarFile> cp) {
|
|
|
|
|
this.cp = cp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<JarFile> getCp() {
|
|
|
|
|
return cp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ClassMetadataReader() {
|
|
|
|
|
this.cp = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void acceptVisitor(byte[] classData, ClassVisitor visitor) {
|
|
|
|
|
new ClassReader(classData).accept(visitor, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void acceptVisitor(String className, ClassVisitor visitor) throws IOException {
|
|
|
|
|
acceptVisitor(getClassData(className), visitor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] getClassData(String className) throws IOException {
|
|
|
|
|
for (JarFile f : cp) {
|
|
|
|
|
if (f.getEntry(className + ".class") != null)
|
|
|
|
|
try (InputStream in = f.getInputStream(f.getEntry(className + ".class"))) {
|
|
|
|
|
return IOHelper.read(in);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return IOHelper.read(IOHelper.getResourceURL(className + ".class"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getSuperClass(String type) {
|
|
|
|
|
if (type.equals("java/lang/Object")) return null;
|
|
|
|
|
try {
|
|
|
|
|
return getSuperClassASM(type);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return "java/lang/Object";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected String getSuperClassASM(String type) throws IOException {
|
|
|
|
|
CheckSuperClassVisitor cv = new CheckSuperClassVisitor();
|
|
|
|
|
acceptVisitor(type, cv);
|
|
|
|
|
return cv.superClassName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Возвращает суперклассы в порядке возрастающей конкретности (начиная с
|
|
|
|
|
* java/lang/Object и заканчивая данным типом)
|
|
|
|
|
*/
|
|
|
|
|
public ArrayList<String> getSuperClasses(String type) {
|
|
|
|
|
ArrayList<String> superclasses = new ArrayList<>(1);
|
|
|
|
|
superclasses.add(type);
|
|
|
|
|
while ((type = getSuperClass(type)) != null)
|
|
|
|
|
superclasses.add(type);
|
|
|
|
|
Collections.reverse(superclasses);
|
|
|
|
|
return superclasses;
|
|
|
|
|
}
|
2018-12-06 05:29:34 +03:00
|
|
|
|
|
|
|
|
|
}
|