Pete が述べたように、これは ASM バイトコード ライブラリを使用して実行できます。実際、そのライブラリには、これらのクラス名の再マッピングを処理するための特別なクラスが付属しています ( RemappingClassAdapter
)。このクラスを使用したクラスローダーの例を次に示します。
public class MagicClassLoader extends ClassLoader {
private final String defaultPackageName;
public MagicClassLoader(String defaultPackageName) {
super();
this.defaultPackageName = defaultPackageName;
}
public MagicClassLoader(String defaultPackageName, ClassLoader parent) {
super(parent);
this.defaultPackageName = defaultPackageName;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
byte[] bytecode = ...; // I will leave this part up to you
byte[] remappedBytecode;
try {
remappedBytecode = rewriteDefaultPackageClassNames(bytecode);
} catch (IOException e) {
throw new RuntimeException("Could not rewrite class " + name);
}
return defineClass(name, remappedBytecode, 0, remappedBytecode.length);
}
public byte[] rewriteDefaultPackageClassNames(byte[] bytecode) throws IOException {
ClassReader classReader = new ClassReader(bytecode);
ClassWriter classWriter = new ClassWriter(classReader, 0);
Remapper remapper = new DefaultPackageClassNameRemapper();
classReader.accept(
new RemappingClassAdapter(classWriter, remapper),
0
);
return classWriter.toByteArray();
}
class DefaultPackageClassNameRemapper extends Remapper {
@Override
public String map(String typeName) {
boolean hasPackageName = typeName.indexOf('.') != -1;
if (hasPackageName) {
return typeName;
} else {
return defaultPackageName + "." + typeName;
}
}
}
}
説明のために、デフォルト パッケージに属する 2 つのクラスを作成しました。
public class Customer {
}
と
public class Order {
private Customer customer;
public Order(Customer customer) {
this.customer = customer;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
これは、再マッピングOrder
前のリストです。
> javap -private -c 注文
「Order.java」からコンパイル
public class Order extends java.lang.Object{
個人顧客の顧客。
公序(顧客);
コード:
0: aload_0
1: 特別な #10 を呼び出します。//メソッド java/lang/Object."":()V
4: aload_0
5: aload_1
6: putfield #13; //フィールドの顧客:LCustomer;
9: 戻る
パブリック カスタマー getCustomer();
コード:
0: aload_0
1: getfield #13; //フィールドの顧客:LCustomer;
4: 戻る
public void setCustomer(顧客);
コード:
0: aload_0
1: aload_1
2: putfield #13; //フィールドの顧客:LCustomer;
5: 戻る
}
これは再マッピングOrder
後のリストです(com.mycompany
デフォルトのパッケージとして使用):
> javap -private -c 注文
「Order.java」からコンパイル
public class com.mycompany.Order extends com.mycompany.java.lang.Object{
プライベート com.mycompany.Customer 顧客;
パブリック com.mycompany.Order(com.mycompany.Customer);
コード:
0: aload_0
1: 特別な #30 を呼び出します。//メソッド "com.mycompany.java/lang/Object"."":()V
4: aload_0
5: aload_1
6: putfield #32; //フィールドの顧客:Lcom.mycompany.Customer;
9: 戻る
public com.mycompany.Customer getCustomer();
コード:
0: aload_0
1: getfield #32; //フィールドの顧客:Lcom.mycompany.Customer;
4: 戻る
public void setCustomer(com.mycompany.Customer);
コード:
0: aload_0
1: aload_1
2: putfield #32; //フィールドの顧客:Lcom.mycompany.Customer;
5: 戻る
}
ご覧のとおり、再マッピングによって へのすべての参照と へのすべての参照が変更されていOrder
ます。com.mycompany.Order
Customer
com.mycompany.Customer
このクラスローダーは、次のいずれかのすべてのクラスをロードする必要があります。
- デフォルトのパッケージに属している、または
- デフォルト パッケージに属する他のクラスを使用します。