用不同的包名动态加载java中的类
是否可以在Java中加载一个类并“伪造”类的包名/规范名?我尝试过这样做,很明显,但是我在用不同的包名动态加载java中的类,java,class,dynamic-class-loaders,Java,Class,Dynamic Class Loaders,是否可以在Java中加载一个类并“伪造”类的包名/规范名?我尝试过这样做,很明显,但是我在ClassDefNotFoundException中得到了一条“类名不匹配”的消息 我这样做的原因是我试图加载一个在默认包中编写的API,这样我就可以直接使用它而不用使用反射。代码将针对表示包和包名导入的文件夹结构中的类进行编译。即: ./com/DefaultPackageClass.class 我目前的代码如下: public Class loadClass(String name) throws Cl
ClassDefNotFoundException
中得到了一条“类名不匹配”的消息
我这样做的原因是我试图加载一个在默认包中编写的API,这样我就可以直接使用它而不用使用反射。代码将针对表示包和包名导入的文件夹结构中的类进行编译。即:
./com/DefaultPackageClass.class
我目前的代码如下:
public Class loadClass(String name) throws ClassNotFoundException {
if(!CLASS_NAME.equals(name))
return super.loadClass(name);
try {
URL myUrl = new URL(fileUrl);
URLConnection connection = myUrl.openConnection();
InputStream input = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1){
buffer.write(data);
data = input.read();
}
input.close();
byte[] classData = buffer.toByteArray();
return defineClass(CLASS_NAME,
classData, 0, classData.length);
} catch (MalformedURLException e) {
throw new UndeclaredThrowableException(e);
} catch (IOException e) {
throw new UndeclaredThrowableException(e);
}
}
也许将API从默认包移动到更合理的位置会更容易?听起来你好像没有访问源代码的权限。我不确定包是否被编码到类文件中,因此简单地移动API类可能值得一试。否则,像JAD这样的Java反编译器通常会做得很好,因此您可以在反编译的源代码中更改包名并重新编译它。您应该能够完成一些工作,尽管在构建时重命名包比在加载时重命名包更容易。,这可以使用ASM字节码库来完成。事实上,该库实际上附带了一个专门用于处理这些类名重新映射()的类。下面是使用此类的类装入器示例:
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 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
}
如您所见,重新映射已将所有Order
引用更改为com.mycompany.Order
,将所有Customer
引用更改为com.mycompany.Customer
此类加载器必须加载以下所有类:
- 属于默认包,或
- 使用属于默认包的其他类
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;
}
}
> 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
}
> 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
}