IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API standards et tierces Java Discussion :

javaagent retransformer les classes déjà chargées


Sujet :

API standards et tierces Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    67
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 67
    Par défaut javaagent retransformer les classes déjà chargées
    Bonjour,
    Vous pouvez faire le test chez vous sans problème il suffit de récupérer la dernière version de ASM Java bytecode manipulation and analysis framework.

    Je veux instrumenter mon code source.

    J'y arrive très bien seulement quelques classes ne sont pas instrumentées car elles sont chargées trop tot (avant même que l'instrumenteur se met en place). Donc si elles sont déjà chargées par le ClassLoader c'est trop tard, je peux plu les instrumenter (car l'instrumentation se fait lors du chargement de la classe par le ClassLoader).

    Heureusement il existe une méthode : Instrumentation.retransformClasses(Class<?> ) que malheureusement je n'arrive pas utiliser.

    Comme vous pouvez le constater dans la doc :
    http://java.sun.com/javase/6/docs/ap...lang.Class...)
    Cette méthode est très capricieuse (à la moindre exception relevée, aucune classe de l'ensemble des classes passées en paramètre à la méthode retransform n'est transformé)

    Bon je vous explique ce que je veux faire:
    Voila la classe que je veux instrumenter dynamiquement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public class ClassTest{
        public static void main(String[] arg){
            String s = new String("0123456789");
             int i = s.indexOf("4");
             System.out.println(i);
        }
    }
    Donc en gros, le résultat de l'instrumentation serait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Je suis dans : ClassTest.main([Ljava.lang.String)V
    Je suis dans : java.lang.String <init>(Ljava.lang.String)V
    Je suis dans : java.lang.String.indexOf(I)I
    je suis dans : java.io.PrintStream(I)V
    Pour cela je crée un agent:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    public class SimpleTransformer2 implements ClassFileTransformer {
         Instrumentation instrum;
     
         public static void premain(String agentArguments, Instrumentation instrumentation) {    
            instrumentation.addTransformer(new SimpleTransformer2(instrumentation),true);    
        }    
     
        public SimpleTransformer2(Instrumentation i) {
            super();
            instrum = i;
            try{
     
                java.util.Vector<Class> v = new java.util.Vector<Class>();
                Class[] cl = instrum.getAllLoadedClasses();
     
                int nb = 0;
                for(int a=0;a<cl.length;a++){
                    if(instrum.isModifiableClass(cl[a])){
                        v.add(cl[a]);
     
                    }
                }
                Class[] cl2 = new Class[v.size()];
                v.toArray(cl2);
                instrum.retransformClasses(cl2);
     
            }catch(Exception e){
                    e.printStackTrace();
            }
     
        }
     
        public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
     
                    //cette instruction me permet de connaitre le nom des classes qui sont passées par la méthode transform
            System.out.println("--->Transform: " + className);
     
            byte[] result = bytes;
            try {
                    //CODE ASM
                    ClassReader reader = new ClassReader(bytes);
    				ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
    				MyClassAdapter mca = new MyClassAdapter(writer, className);
    				reader.accept(mca , ClassReader.SKIP_DEBUG);
    				result = writer.toByteArray();		             
            }
            catch(Exception e) {
                e.printStackTrace();
            }
            return result;
        }
     
    /** Après il y a mon code en ASM qui instrumente les différentes méthodes en indiquant le nom des méthodes qui sont appelées*/
    }
    Pour ceux qui voudrai tester voila le code qu'il faut insérer à la place du dernier commentaire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    /********************************ClassAdapter**************************************/	
     
        private class MyClassAdapter extends ClassAdapter {
     
    		private String className;
     
    		MyClassAdapter(ClassVisitor cv, String theClass) {
    		    super(cv);
    		    className = theClass;
     
    		}
     
    		@Override public void visit(int arg0, int access, String name, String signature,String superName, String[] interfaces) {
    			System.out.println(className);
    			cv.visit(arg0, access, name, signature, superName, interfaces);	
    		}
     
    		@Override public MethodVisitor visitMethod(int arg0, String name, String descriptor, String signature, String[] exceptions) {
    		    MethodVisitor mv = cv.visitMethod(arg0, name, descriptor, signature, exceptions);
    		/*	mv = new TraceMethodVisitor(mv){
    				    @Override public void visitEnd(){
    				    		mv.visitCode();
    				    		print(new PrintWriter(System.out));
    				    }
    			    };
    		*/	    
    		    return new MyMethodAdapter(mv,className,name,descriptor);
    		}
        }
     
    /********************************MethodAdapter**************************************/	
     
        private class MyMethodAdapter extends MethodAdapter {
    	private String methodName;
    	private String methodDescriptor;
    	private String className;
     
    		MyMethodAdapter(MethodVisitor mv, String theClass, String name, String descriptor) {
    		    super(mv);
    		    methodName = name;
    		    methodDescriptor = descriptor;
    		    className = theClass;
    		}
     
    		@Override public void visitCode() {
    			mv.visitCode();
    			//Every method print her name at the beginning
    			mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
    			mv.visitLdcInsn("Je suis dans " + className + "." + methodName + "(" + methodDescriptor + ") called");
    			mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
     
    		}
     
    	}
    Je crée un fichier MANIFEST.MF:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Manifest-Version: 1.0 
    Premain-Class: SimpleTransformer2
    Can-Retransform-Classes: true
    Can-Redefine-Classes: true
    Boot-Class-Path: asm-3.2.jar asm-analysis-3.2.jar asm-commons-3.2.jar asm-tree-3.2.jar asm-util-3.2.jar asm-xml-3.2.jar
    voila la suite de commande que je tape (sous windows):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    set CLASSPATH=%CLASSPATH%;[...]\asm-3.2\lib\asm-3.2.jar;[...]\asm-3.2\lib\asm-util-3.2.jar
    javac *.java
    jar -cfm test.jar MANIFEST.MF *
    java -javaagent:test.jar ClassTest
    Le résultat que j'obtiens actuellement:
    Je suis dans ClassTest.main

    Il n'a pas détecter le String<init> et le String.indexOf parce que la classe String n'a pas été instrumentée.

    Est ce que quelqu'un a une idée? Merci pour vos réponses

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    67
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 67
    Par défaut En fait je vais pouvoir répondre
    il faut ajouter le parametre Agent-Class dans le manifest
    et définir la méthode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     public static void agentmain(String agentArgs, Instrumentation inst)
    Class[] classes = inst.getAllLoadedClasses();
           List<Class> candidates = new ArrayList<Class>();
                  for (Class c : classes) {
             if (inst.isModifiableClass(c)){
               candidates.add(c);
             }
           }
           System.out.println("There are "+candidates.size()+" classes");
       try {
         // if we have matching candidates, then
         // retransform those classes so that we
         // will get callback to transform.
         if (! candidates.isEmpty()) {
             Iterator it = candidates.iterator();
             while(it.hasNext()){
                 Class c = (Class)it.next();
                 System.out.println(" ========================> In Progress: "+c.getName());
               inst.retransformClasses(c/*candidates.toArray(new Class[0])*/);
           }
         }else{
             System.out.println("candidates.isEmpty()");
         }
       } catch (Exception uce) {
           uce.printStackTrace();
       }
     }
    du coup j'ai d'autres problème que je vais poster en dessous

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    67
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 67
    Par défaut Probleme d'execution de méthode ajouter dynamiquement
    j'ajoute ce code au début que toutes les méthodes non <init>

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    mv.visitMethodInsn(INVOKESTATIC,"___Singleton","getInstance","()L___Singleton;");
           mv.visitLdcInsn(methodName);
          mv.visitMethodInsn(INVOKEVIRTUAL,"___Singleton","printString","(Ljava/lang/String;)V");
    En gros j'appelle printString de la classe ___Singleton.
    voila a quoi ressemble cette méthode:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     public void printString(String s){
           try{
               //ca plante
               s.equals("<init>");
           }catch(Exception e){
               e.printStackTrace();
           }
    à partir du moment ou je manipule la string s le program plante!
    l'erreur c'est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at ../../../src/share/instrument/JPLISAgent.c line: 806
    Si je commente cette ligne le programme fonctionne.
    En gros je ne peux pas faire d'opération (dans ma classe ___Singleton) sur les classes que j'ai instrumenté.
    Donc ma classe ___Singleton est complètement inutile.

    merci pour vos réponses

Discussions similaires

  1. Visite de l'ast sur toutes les classes chargées
    Par Alain Defrance dans le forum Groovy
    Réponses: 0
    Dernier message: 19/07/2010, 17h48
  2. outil pour connaitres les classes chargés
    Par riadhhwajdii dans le forum Général Java
    Réponses: 4
    Dernier message: 28/09/2009, 16h50
  3. Réponses: 4
    Dernier message: 13/09/2006, 14h17
  4. Réponses: 31
    Dernier message: 30/03/2006, 16h57
  5. Les classes amies en Delphi
    Par Bruno75 dans le forum Langage
    Réponses: 3
    Dernier message: 02/09/2003, 19h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo