开发者

Invoke a bytecode class method, java

Im new to java, (i use to program in .NET, Lua ...) and i started to use ASM. so i can't use any methods of the class "Foo", how can i invoke these methods?

many thanks...

code:

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));

   }

}

* NEW CODE WORKING *

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);
            m开发者_开发问答v.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));

}

}

Thanks Paŭlo Ebermann, next step i ll try class loading with instance ( i think something like "Class s= new simple()" ).


It looks like your problem is here:

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

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

klass.forName("Foo") is actually equivalent to Class.forName("Foo"), which results in Class.forName("Foo", nclass.class.getClassLoader());.

The class loader which loaded nclass obviously does not know a Foo class, since it was created by your anonymous class loader (which is a child of this class loader). So, don't use this forName call here, but simply use your klass object to get the method and invoke it.


And of course, invoking and retrieving a method works not like you did.

  • The getMethod and getDeclaredMethod take beside the name a list of argument types (not return types) - in your case getNome has no arguments, so it should be:

    Method  method = klass.getDeclaredMethod ("getNome");
    
  • the invoke methods first argument is an object of the methods receiving type (Foo in your case), or null for static methods. The following arguments are the parameters to the method (i.e. none in your case). So you should use here:

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

    It may be that the argument is simply ignored in your case, so c might not get an error. But there still is no reason to use a class object here, if you are not actually invoking a method of class Class by reflection.

This all is assuming your error occurs in your forName call and not already earlier. Please learn to describe your error message, so we don't have to guess.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜