Как сохранить определение класса динамически сгенерированного Java-класса с использованием ASM?

Я расширил класс динамически, используя ASM. Я использовал метод defineClass без аргумента ProtectionDomain. Когда я пытаюсь использовать этот класс в другом классе, я получаю java.lang.NoClassDefFound Error. Как я могу сохранить или получить определение класса, который определен во время выполнения, используя ASM?

2 ответа

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

Вот пример кода, у меня есть интерфейсный калькулятор

package com.Executor;

public interface Calculator {   
    int add(int left, int right);
}

ниже приведен код для динамического создания класса, который реализует и переопределяет метод.

package com.Executor;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class DynamicClassWriter {

    public static class DynamicClassLoader extends ClassLoader {
        public Class<?> defineClass(String name, byte[] b) {
            return defineClass(name, b, 0, b.length);
        }
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {

        /*Instantiate the ASM ClassWriter*/
        ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

        /*Initialize the writer with the specifications*/
        classWriter.visit(Opcodes.V1_7,                             // Java 1.7 
                Opcodes.ACC_PUBLIC,                                 // public class
                "com/Executor/CustomClass",                 // package and name
                null,                                               // signature (null means not generic)
                "java/lang/Object",                                 // superclass
                new String[]{ "com/Executor/Calculator" });         // interfaces (in this case Calculator interface inside com/Executor Package)


        /* Build constructor */
        MethodVisitor methodVisitor = classWriter.visitMethod(
                Opcodes.ACC_PUBLIC,                         // public method
                "<init>",                           // method name 
                "()V",                              // descriptor
                null,                               // signature (null means not generic)
                null);                              // exceptions (array of strings)


        methodVisitor.visitCode();                            // Start the code for this method
        methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);                 // Load "this" onto the stack
        methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,          // Invoke an instance method (non-virtual)
                "java/lang/Object",                 // Class on which the method is defined
                "<init>",                           // Name of the method
                "()V");                              // Descriptor;                             
        methodVisitor.visitInsn(Opcodes.RETURN);             // End the constructor method
        methodVisitor.visitMaxs(1, 1);                        // Specify max stack and local vars

        /* Build 'add' method (Implementing Interface method)*/
        MethodVisitor mv = classWriter.visitMethod(
                Opcodes.ACC_PUBLIC,                         // public method
                "add",                              // name
                "(II)I",                            // descriptor
                null,                               // signature (null means not generic)
                null);                              // exceptions (array of strings)
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ILOAD, 1);                  // Load int value onto stack
        mv.visitVarInsn(Opcodes.ILOAD, 2);                  // Load int value onto stack
        mv.visitInsn(Opcodes.IADD);                         // Integer add from stack and push to stack
        mv.visitInsn(Opcodes.IRETURN);                      // Return integer from top of stack
        mv.visitMaxs(2, 3);                         // Specify max stack and local vars
        classWriter.visitEnd();                              // Finish the class definition


        DynamicClassLoader loader = new DynamicClassLoader();
        Class<?> clazz = loader.defineClass("com.Executor.CustomClass", classWriter.toByteArray());
        System.out.println(clazz.getName());
        Calculator calc = (Calculator)clazz.newInstance();
        System.out.println("2 + 2 = " + calc.add(2, 2));

    }
}

Выход

com.Executor.CustomClass 2 + 2 = 4

Другие вопросы по тегам