Добавление интерфейса к преобразованному классу, если присутствует аннотация - PullRequest
2 голосов
/ 24 марта 2011

Я пишу преобразователь байт-кода, используя ClassAdapter платформы asm. Если в классе присутствует пользовательская аннотация, я хочу добавить несколько методов и заставить класс реализовать интерфейс. Добавление методов работает нормально, но мне интересно, как лучше всего заставить класс реализовать интерфейс. Поскольку visitAnnotation вызывается только после visit, мне нужно каким-то образом отложить вызов метода супер-посещения и буферизовать всю необходимую информацию до этого момента.

Кто-нибудь реализовывал нечто подобное? Должен ли я использовать для этого дерево api asm, хотя документация к пакету рекомендует избегать его, если это возможно?

Вот общая структура преобразования:

public class MyClassAdapter extends ClassAdapter {
    private String  classname;
    private boolean instrument;

    public PropertyChangeSupportAdapter(ClassVisitor cv) {
        super(cv);
    }

    @Override
    public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
        this.classname = name;
    }

    @Override
    public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
        if (desc.equals("Lmypackage/MyAnnotation;")) {
            instrument = true;
            System.out.println("Instrumenting " + classname);
        }
        return super.visitAnnotation(desc, visible);
    }

    @Override
    public void visitEnd() {
        if (instrument) {
            // add methods
        }
    }
}

1 Ответ

2 голосов
/ 30 марта 2011

Я использовал комбинацию ClassNode и ClassAdapter apis.Сначала файл класса анализируется в ClassNode:

ClassReader cr = new ClassReader(inputStream);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);

Затем можно проверить, содержит ли cn.visibleAnnotation или cn.invisibleAnnotations мою аннотацию, а также, если класс уже реализует интерфейс, который я хочу добавить.В этом случае второй шаг можно пропустить.ClassNode может быть преобразован с помощью API ClassAdapter, как в вопросе:

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
CheckClassAdapter ca = new CheckClassAdapter(cw);
ClassVisitor cv = new PropertyChangeSupportAdapter(ca);
cn.accept(cv);

В примечании к документации , которое послужило причиной моего вопроса, упоминается большая разница в производительности.между этими apis:

Почти в два раза быстрее читать, «модифицировать» и писать класс с ClassAdapter, чем с ClassNode.... По этой же причине рекомендуется не использовать этот класс адаптер, когда это возможно.

После перечитывания этого снова, похоже, возникает разница с использованием ClassNode для манипулирования байтовыми кодами.Однако я не тестировал это гибридное решение.

...