Что я хочу сделать, так это: у меня есть адаптер ClassVisitor, при входе в метод visit
я хочу знать, является ли класс AncestorClass
классом-предком этого класса? Я пытался использовать отражение (Class.forname(...)
) следующим образом:
МойТрансформер.класс:
public class MyTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (className == null){
return classfileBuffer;
}
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
CollectionCVAdapter mca = new MyCVAdapter(cw, className);
cr.accept(mca, 0);
return cw.toByteArray();
}
}
MyCVAdapter.класс:
class MyCVAdapter extends ClassVisitor {
private String className;
private boolean isDescendantClass;
CollectionCVAdapter(ClassVisitor classVisitor, String className){
super(Opcodes.ASM5, classVisitor);
this.className = className;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
// check if this class is a descendant class of AncestorClass.class
try{
Class superClass = Class.forName(superName.replace("/", "."));
do {
if (superClass == AncestorClass.class) {
this.isDescendantClass= true;
break;
}
superClass = superClass.getSuperclass();
} while (superClass != null);
}catch (Exception e){
e.printStackTrace();
}
super.visit(version, access, name, signature, superName, interfaces);
}
...
}
но проблема в том, что я также хочу инструментировать родительский класс инструментированного класса. Я обнаружил, что как только Class.forName()
загрузит родительский класс, родительский класс не попадет в метод transform
. Это означает, что родительский класс больше не может быть инструментирован. Итак, есть ли альтернативы, чтобы узнать, является ли класс потомком класса AncestorClass
?
ClassReader.getSuperName()
. Второе: загрузите файлы классов с помощьюloader.getResourceAsStream(superName + ".class")
. Разберите это с помощью ClassReader. - person Johannes Kuhn   schedule 26.07.2020ClassLoader
архитектуре нет пуленепробиваемого подхода.getResourceAsStream(internalName + ".class")
- это лучший способ получить байт-код без загрузки класса, если конкретная реализация загрузчика классов последовательно предоставляет содержимое файлов классов в качестве ресурса (все стандартные загрузчики делают). С модульным кодом код всегда загружается стандартным загрузчиком, делегирующимModuleReader
для получения байт-кода, поэтомуgetResourceAsStream
всегда будет соответствоватьloadClass
в пределах одного и того жеModuleLayer
. - person Holger   schedule 27.07.2020ModuleReader
? Я не слышал этого раньше. В методеtransform
я могу получить аргументClassLoader
, чтобы использоватьgetResourceAsStream
. Но в других случаях, когда у меня нет доступногоClassLoader
и я хочу использоватьgetResourceAsStream
для получения байт-кода, я обычно используюClass.forName(className).getClassLoader().getResourceAsStream
. На самом деле, я не уверен, какой загрузчик может дать мне нужный байт-код. Есть ли более изящные способы? - person Instein   schedule 27.07.2020ClassFileTransformer
, вы должны использоватьClassLoader
, который был предоставлен в качестве первого аргумента для методаtransform
. Если этоnull
, используйтеClassLoader.getSystemResourceAsStream(…)
. - person Holger   schedule 27.07.2020null
. Точно так же вы можете использовать ярлык всякий раз, когда имя класса начинается сjava/
. - person Holger   schedule 27.07.2020