2016-05-24 9 views
1

Ich versuche, eine kompilierte Klasse zu modifizieren (Quellcode ist nicht verfügbar), die ich zum Beispiel alle Verweise auf java.lang.Object zu some.packageName.SomeClass ändern möchte.Ändern Sie alle Klassenreferenzen in einer kompilierten Klasse

von Referenzen, die ich meine:

  • Feldtypen
  • Methoden Rückgabetypen
  • Methoden Argumenttypen
  • Supertype
  • Variablen-Typen in Methodenrümpfe
  • Statische Klassenreferenzen (zB java.lang.Object.class)
  • Gene ric Typparameter
  • Etc.

Grundsätzlich von diesem Beispiel should't die modifizierte Klasse Lage sein, direkt die java.lang.Object Klasse zugreifen, sondern nur durch some.packageName.SomeClass. Bitte beachten Sie, dass die Beispielklasse eine beliebige Klasse aus der JRE sein kann oder nicht. Der angegebene Ersatz verhält sich genau so, wie das Original erwartet wird.

Ist dies mit BCEL oder mit Javassist möglich? Wenn nicht, gibt es eine andere Bibliothek, die Funktionen zur Erreichung dieses Ziels bietet?

+0

Warum sollte jemand ändern eine kompilierte Klasse? –

+0

@Vishal Kamat, wenn du nicht weißt warum, bedeutet das, dass du es nicht brauchst. Es kann in einigen Fällen nützlich sein, zum Beispiel eine zusätzliche Methode hinzuzufügen und eine Schnittstelle in einer Klasse zu implementieren, in der Sie nicht den Quellcode haben. In meinem Fall ist nur ein Sandboxing-Test. –

+0

In diesem Fall ist AOP dein Freund. Viele Sachen darin, genau das zu tun, was du erwähnt hast –

Antwort

1

Ich habe es nicht versucht, aber Javassist und ASM kann sicherlich konstant Pool in der Klasse ändern. Dies ist der Ort, an dem solche Referenzen in der Klassendatei gespeichert werden.

+0

Wird es ausreichen, nur den konstanten Pool zu modifizieren?Gibt es außer der Reflektion noch eine andere Möglichkeit, bei der eine Klasse, auf die im Konstantenpool nicht verwiesen wird, in einer anderen Klasse noch sichtbar ist? –

+0

Alle Klassen/Felder/Methodenreferenzen gehen durch den konstanten Pool – Nikem

+0

Ich werde es versuchen –

0

Ich benutze ASM und das ist unglaublich einfach. Ich habe eine Implementierung von org.objectweb.asm.commons.Remapper, die Namen und Deskriptoren von Klassen zu neuen ändert.

Zum Beispiel eines der Verfahren sieht wie folgt aus:

@Override 
public String mapDesc(String desc) { 
    return super.mapDesc(StringUtil.fixDesc(desc, renamed)); 
} 

Eine Beschreibung sieht wie folgt aus: Lcom/example/Klasse;. Das Feld 'umbenannt', dass ich feedDesc feed ist eine Karte der Klassenzuordnungen, die ich gemacht habe, die die alten zu neuen Werten enthalten. Also, wenn ich com/example/AAA in com/example/BBB machen wollen füttere ich die vor und nach den Werten in die Karte und rufen Sie die remapper wie so:

/** 
* Given a map of ClassNodes and mappings, returns a map of class names to 
* class bytes. 
*/ 
public static Map<String, byte[]> process(Map<String, ClassNode> nodes, Map<String, MappedClass> mappings) { 
    Map<String, byte[]> out = new HashMap<String, byte[]>(); 
    RemapperImpl mapper = new RemapperImpl(mappings); 
    for (ClassNode cn : nodes.values()) { 
     ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 
     ClassVisitor remapper = new ClassRemapper(cw, mapper); 
     cn.accept(remapper); 
     out.put(mappings.get(cn.name).getNewName(), cw.toByteArray()); 
    } 
    return out; 
}