2016-06-06 15 views
1

In einer großen Anzahl von Klassen, die von der gemeinsamen Vorfahrenklasse abgeleitet sind, habe ich die Methode something() deren Verhalten ich ändern möchte, um die Ausführungszeit zu messen. definiere ich zwei weitere Methoden in der gemeinsamen Vorfahren KlasseJavassist: Kopiermethode mit Debug-Informationen?

// in the common ancestor class: 
// this method is defined in all derived classes 
public void something() { 
    System.out.println("something{"); 
    System.out.println("something}"); 
} 
// the body of this method will replace the body of something() 
public void measuredSomething() { 
    System.out.println("measuredSomething{"); 
    roomForSomething(); 
    System.out.println("measuredSomething}"); 

} 
// the body of this method will be replaced by the body of something() 
public void roomForSomething() { 
    // this code will be replaced with something else 
    System.out.println("roomForSomething{"); 
    System.out.println("roomForSomething}"); 
} 

Und ich tue das Ersetzen mit Javassist:

// someClass is known 
String superClassName = someClass.getName(); 
String className = superClassName + "__proxy"; 
CtClass ctSuperClass = ClassPool.getDefault().get(superClassName); 
CtClass ctClass = ClassPool.getDefault().makeClass(className); 
ctClass.setSuperclass(ctSuperClass); 

// roomForSomething := something 
CtMethod methodSomething = ctSuperClass.getMethod("something", "()V"); 
CtMethod methodSomething2 = CtNewMethod.copy(methodSomething, "roomForSomething", ctClass, null); 

ctClass.addMethod(methodSomething2); 

// something := measuredSomething 
// (and measuredSomething() will call roomForSomething()) 
CtMethod methodMeasuredSomething = ctSuperClass.getMethod("measuredSomething", "()V"); 
CtMethod methodMeasuredSomething2 = CtNewMethod.copy(methodMeasuredSomething, "something", ctClass, null); 

ctClass.addMethod(methodMeasuredSomething2); 

someClass = ctClass.toClass(); 
result = someClass.newInstance(); 

Und es funktioniert. Der Debugger kann den ausführenden Code jedoch nicht anzeigen.

Wie kopiere ich die Debugging-Informationen zusammen mit dem Byte-Code, so dass der Debugger die ausführende Quelle anzeigen würde?

(Es ist nicht möglich, wenn der Methodencode modifiziert wird, soll aber in diesem speziellen Fall möglich sein.)

((Ich habe schlug die Methode something() in zwei Verfahren aufgeteilt, auf die gleiche Art und Weise ., da es Thread.run() außer Kraft zu setzen sind, und Thread.start() aufzurufen ich bin gebeten worden, eine solche Änderung zu vermeiden))

UPDATE

Die folgende Methode etwas bessere Ergebnisse gibt. t Der Debugger stoppt in der über CtMethod.make() generierten Funktion nur, wenn er von der aufgerufenen Funktion zurückkehrt; die generierte Funktion ist in der Stack-Trace sichtbar; Die Quelle der generierten Funktion ist nicht verfügbar.

// something := measuredSomething 
CtMethod methodSomething = CtMethod.make("public void something() {super.measuredSomething();}", ctClass); 
ctClass.addMethod(methodSomething); 

// roomForSomething := something 
CtMethod methodRoomForSomething = CtMethod.make("public void roomForSomething() {super.something();}", ctClass); 
ctClass.addMethod(methodRoomForSomething); 

Es wäre wirklich gut, wenn es möglich wäre, die Quelle der generierten Funktion anzuzeigen.

Antwort

0

Ich glaube nicht, dass Sie direkt den injizierten Code mit Javassist debuggen können, da diese Bibliothek nur den Bytecode modifizieren kann (also eigentlich wird der Quellcode nicht geändert). Dies bedeutet, dass Ihr Debugger nicht auf den Code zugreifen kann, den Sie injiziert haben, da er im Grunde nicht existiert (es ist nur eine grafische Möglichkeit, Ihre Bytecode-Verarbeitung auszudrücken).

Übrigens hatte ich das gleiche Problem und mein Ziel war es, die Methode roomForSomething zu debuggen. Meine Lösung war dies: Zuerst deklariere die Methode, die du debuggen willst (in deinem Fall roomForSomething()) in einer Klasse und mache sie statisch.

package p.a.c.k.a.g.e; 
public class ClassName{ 
    public static void roomForSomething(){ 
     // here you can debug 
    } 
} 

Nachdem Sie einfach mit JavaSist einen Aufruf dieser statischen Methode in die modifizierte Methode injizieren können. Selbst wenn in der Klasse nicht die Klasse importiert wird, in der Sie "roomForSomething" definiert haben, können Sie den vollständig qualifizierten Namen der Klasse wie im Beispiel angeben.

// roomForSomething := something 
CtMethod methodRoomForSomething = CtMethod.make("public void randomName() {p.a.c.k.a.g.e.ClassName.roomForSomething()}", ctClass); 
ctClass.addMethod(methodRoomForSomething); 

Mit dieser Lösung Sie einen Haltepunkt in den „roomForSomething“ Code einstellen.