As Pete mentioned이 작업은 ASM 바이트 코드 라이브러리를 사용하여 수행 할 수 있습니다. 사실,이 라이브러리는 실제로 이러한 클래스 이름 재 매핑 (RemappingClassAdapter
)을 처리하기위한 클래스와 함께 제공됩니다.
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;
}
}
:
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;
}
}
}
}
가 나는 기본 패키지에 속하는 둘 다 두 개의 클래스를 생성, 설명하기 : 다음은이 클래스를 사용하여 클래스 로더의 예입니다
이전에이 표시됩니다.
> javap -private -c Order
Compiled from "Order.java"
public class com.mycompany.Order extends com.mycompany.java.lang.Object{
private com.mycompany.Customer customer;
public com.mycompany.Order(com.mycompany.Customer);
Code:
0: aload_0
1: invokespecial #30; //Method "com.mycompany.java/lang/Object"."":()V
4: aload_0
5: aload_1
6: putfield #32; //Field customer:Lcom.mycompany.Customer;
9: return
public com.mycompany.Customer getCustomer();
Code:
0: aload_0
1: getfield #32; //Field customer:Lcom.mycompany.Customer;
4: areturn
public void setCustomer(com.mycompany.Customer);
Code:
0: aload_0
1: aload_1
2: putfield #32; //Field customer:Lcom.mycompany.Customer;
5: return
}
당신이 볼 수 있듯이
가, 다시 매핑이
com.mycompany.Order
모든
Order
참조를 변경하고 모든
Customer
참조했습니다
> javap -private -c Order
Compiled from "Order.java"
public class Order extends java.lang.Object{
private Customer customer;
public Order(Customer);
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."":()V
4: aload_0
5: aload_1
6: putfield #13; //Field customer:LCustomer;
9: return
public Customer getCustomer();
Code:
0: aload_0
1: getfield #13; //Field customer:LCustomer;
4: areturn
public void setCustomer(Customer);
Code:
0: aload_0
1: aload_1
2: putfield #13; //Field customer:LCustomer;
5: return
}
이은 (기본 패키지로 com.mycompany
사용) 매핑 후 Order
의 목록입니다 com.mycompany.Customer
. 기본 패키지에 속한
- 기본 패키지에 속한, 또는
- 사용하는 다른 클래스 :
이 클래스 로더는 모든 중 클래스를로드해야합니다.
아니요, 출처에 액세스 할 수 없습니다. 클래스를 디렉토리로 옮기는 것은 컴파일시에는 보이지만 런타임에는 작동하지 않습니다. 가능하다면 수업을 해킹하지 않을 것입니다. –
런타임에 클래스의 패키지를 변경하는 것이 해킹이 아니라는 말입니까? 나에게 문제는 단지 더 나쁜 해킹이고 다른 하나를 사용하는 것이다. – FelixM