2011-03-30 2 views
1

Im nouveau à Java, (j'ai l'habitude de programmer dans .NET, Lua ...) et j'ai commencé à utiliser ASM. donc je ne peux pas utiliser les méthodes de la classe "Foo", comment puis-je invoquer ces méthodes?Invoquer une méthode de classe de bytecode, java

merci beaucoup ...

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

    } 

} 

* NOUVEAU CODE DE TRAVAIL *

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

} 

} 

Merci paulo Ebermann, étape suivante i vais essayer le chargement des classes par exemple (Je pense quelque chose comme "Class s = new simple()").

+0

Quel est le résultat actuel de votre code? –

Répondre

2

Il semble que votre problème est ici:

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

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

klass.forName("Foo") est en fait équivalent à Class.forName("Foo"), qui se traduit par Class.forName("Foo", nclass.class.getClassLoader());.

Le chargeur de classe qui a chargé nclass ne connaît évidemment pas de classe Foo, puisqu'il a été créé par votre chargeur de classe anonyme (qui est un enfant de ce chargeur de classe). Donc, n'utilisez pas cet appel forName ici, mais utilisez simplement votre objet klass pour obtenir la méthode et l'invoquer.


Et bien sûr, l'invocation et la récupération d'une méthode fonctionne pas comme vous l'avez fait.

  • Le getMethod et getDeclaredMethod prendre à côté du nom d'une liste des types d'arguments (non types de retour) - dans votre cas getNome n'a pas d'arguments, il devrait donc être:

    Method method = klass.getDeclaredMethod ("getNome"); 
    
  • les méthodes d'Invoke le premier argument est un objet du type de réception des méthodes (Foo dans votre cas) ou null pour les méthodes statiques. Les arguments suivants sont les paramètres de la méthode (c'est-à-dire aucun dans votre cas). Vous devez donc utiliser ici:

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

    Il se peut que l'argument est tout simplement ignoré dans votre cas, alors c pourrait ne pas obtenir une erreur. Mais il n'y a toujours aucune raison d'utiliser un objet de classe ici, si vous n'appelez pas réellement une méthode de classe Class par réflexion.

Tout cela est en supposant que votre erreur se produit dans votre forName appel et pas encore plus tôt. S'il vous plaît apprendre à décrire votre message d'erreur, donc nous n'avons pas à deviner.

+0

J'ai trouvé un bogue, j'ai foiré quelques déclarations "simple" et "Foo" et ensuite j'ai eu une erreur, merci pour votre explication rapide! ... – xxleite

Questions connexes