调用一个字节码类方法,java

时间:2011-03-30 21:48:41

标签: java class assembly java-bytecode-asm

我是java新手,(我用.NET编程,Lua ...),我开始使用ASM。 所以我不能使用“Foo”类的任何方法,我如何调用这些方法?

非常感谢...

代码:

package com.teste;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Opcodes.*;

public class nclass {

public static void main(String[] args) throws Exception {

    Class<?> klass = new ClassLoader(nclass.class.getClassLoader()) {
        public Class<?> defineClass() {

            ClassWriter cw = new ClassWriter(0);
            FieldVisitor fv;
            MethodVisitor mv;
            //
            Label l0;
            Label l1;

            cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
                    "Foo", null, "java/lang/Object", null);

            for (int i = 0; i < 3; i++) {
                fv = cw.visitField(0, "value" + i, "I", null, null);
                fv.visitAnnotation("LBar;", true).visitEnd();
            }

            fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "nome", "Ljava/lang/String;", null, null);
            fv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(2, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lsimple;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "setNome", "(Ljava/lang/String;)V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(6, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.PUTSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("value", "Ljava/lang/String;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "getNome", "()Ljava/lang/String;", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(7, l0);
            mv.visitFieldInsn(Opcodes.GETSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(1, 0);
            mv.visitEnd();


            cw.visitEnd();

            byte[] bytes = cw.toByteArray();

            return defineClass("Foo", bytes, 0, bytes.length);
        }
    }.defineClass();

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + f.getName());
    }

    for (Method f : klass.getDeclaredMethods()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }

    Class<?> c= klass.forName("Foo");

    Method  method = c.getDeclaredMethod ("getNome", String.class);
    System.out.println(method.invoke(c));

   }

}

*新代码工作*

package com;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Opcodes.*;

public class simple {

/**
 * @param args
 * @throws NoSuchMethodException 
 * @throws SecurityException 
 * @throws InvocationTargetException 
 * @throws IllegalAccessException 
 * @throws IllegalArgumentException 
 */
public static void main(String[] args) throws SecurityException,      NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {

    Class<?> klass = new ClassLoader(simple.class.getClassLoader()) {
        public Class<?> defineClass() {

            ClassWriter cw = new ClassWriter(0);
            FieldVisitor fv;
            MethodVisitor mv;
            //
            Label l0;
            Label l1;

            cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
                    "simple", null, "java/lang/Object", null);

            for (int i = 0; i < 3; i++) {
                fv = cw.visitField(0, "value" + i, "I", null, null);
                fv.visitAnnotation("LBar;", true).visitEnd();
            }

            fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "nome", "Ljava/lang/String;", null, null);
            fv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(2, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lsimple;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "setNome", "(Ljava/lang/String;)V", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(6, l0);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.PUTSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.RETURN);
            l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("value", "Ljava/lang/String;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "getNome", "()Ljava/lang/String;", null, null);
            mv.visitCode();
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(7, l0);
            mv.visitFieldInsn(Opcodes.GETSTATIC, "simple", "nome", "Ljava/lang/String;");
            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(1, 0);
            mv.visitEnd();


            cw.visitEnd();

            byte[] bytes = cw.toByteArray();

            return defineClass("simple", bytes, 0, bytes.length);
        }
    }.defineClass();

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }

    for (Field f : klass.getDeclaredFields()) {
        System.out.println(f + " " + f.getName());
    }

    for (Method f : klass.getDeclaredMethods()) {
        System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
    }
    Method  setNome = klass.getDeclaredMethod("setNome", String.class);
    Method  getNome = klass.getDeclaredMethod("getNome");

    setNome.invoke(klass,"this sucks!");

    System.out.println(getNome.invoke(null));

}

}

感谢PaŭloEbermann,下一步我将尝试使用实例加载类(我认为类似“Class s = new simple()”)。

1 个答案:

答案 0 :(得分:2)

看起来你的问题就在这里:

 Class<?> c= klass.forName("Foo");

 Method  method = c.getDeclaredMethod ("getNome", String.class);
 System.out.println(method.invoke(c));

klass.forName("Foo")实际上相当于Class.forName("Foo"),结果为Class.forName("Foo", nclass.class.getClassLoader());

加载nclass的类加载器显然不知道Foo类,因为它是由您的匿名类加载器(它是此类加载器的子级)创建的。因此,请不要在此处使用此forName调用,只需使用您的klass对象来获取方法并调用它。


当然,调用和检索方法与您的方法不同。

  • getMethodgetDeclaredMethod在名称旁边加上参数类型列表(不是返回类型) - 在您的情况下getNome没有参数,所以它应该是:

    Method  method = klass.getDeclaredMethod ("getNome");
    
  • invoke方法第一个参数是接收类型(在您的情况下为Foo)的方法的对象,或者是静态方法的null。以下参数是方法的参数(即在您的情况下没有)。所以你应该在这里使用:

    System.out.println(method.invoke(null));
    

    在您的情况下,可能只是忽略了参数,因此c可能不会出错。但是如果你实际上没有通过反射调用类Class的方法,那么仍然没有理由在这里使用类对象。

这一切都假设您的forName电话中发生了错误,而且之前尚未发生错误。请学习描述您的错误消息,因此我们不必猜测。