在java中动态加载一个具有不同包名的类
是否可以在 Java 中加载类并“伪造”类的包名称/规范名称?我尝试这样做,这是显而易见的方法,但我在 ClassDefNotFoundException
中收到“类名不匹配”消息。
我这样做的原因是我试图加载一个在默认包中编写的 API,以便我可以直接使用它而不使用反射。该代码将针对表示包和包名称导入的文件夹结构中的类进行编译。即:
./com/DefaultPackageClass.class
// ...
import com.DefaultPackageClass;
import java.util.Vector;
// ...
我当前的代码如下:
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);
}
}
Is it possible to load a class in Java and 'fake' the package name/canonical name of a class? I tried doing this, the obvious way, but I get a "class name doesn't match" message in a ClassDefNotFoundException
.
The reason I'm doing this is I'm trying to load an API that was written in the default package so that I can use it directly without using reflection. The code will compile against the class in a folder structure representing the package and a package name import. ie:
./com/DefaultPackageClass.class
// ...
import com.DefaultPackageClass;
import java.util.Vector;
// ...
My current code is as follows:
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);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
正如皮特提到的,这可以使用 ASM 字节码库来完成。事实上,该库实际上附带了一个专门用于处理这些类名重新映射的类(
RemappingClassAdapter
)。下面是使用此类的类加载器的示例:为了说明这一点,我创建了两个类,它们都属于默认包:
这
是
Order
before 任何重新映射:这是
Order
after重新映射的列表(使用com.mycompany
作为默认包):如您所见,重新映射已更改对
com.mycompany.Order
的所有Order
引用以及对com.mycompany.Customer
的所有Customer
引用代码>.该类加载器必须加载以下所有类:
As Pete mentioned, this can be done using the ASM bytecode library. In fact, that library actually ships with a class specifically for handling these class name re-mappings (
RemappingClassAdapter
). Here is an example of a class loader using this class:To illustrate, I created two classes, both of which belong to the default package:
and
This is the listing of
Order
before any re-mapping:This is the listing of
Order
after remapping (usingcom.mycompany
as the default package):As you can see, the remapping has changed all
Order
references tocom.mycompany.Order
and allCustomer
references tocom.mycompany.Customer
.This class loader would have to load all classes that either:
您应该能够使用 ASM 进行一些修改,尽管在以下位置重命名一次包会更容易构建时而不是加载时。
You should be able to knock something up with ASM, though it would be easier to do the package rename once at build time rather than at load time.
也许将 API 从默认包移动到更合理的位置会更容易?听起来您无权访问源代码。我不确定包是否被编码到类文件中,因此简单地移动 API 类可能值得一试。否则,像 JAD 这样的 Java 反编译器通常会做得很好,因此您可以更改反编译源中的包名称并重新编译。
Maybe it would be easier to move the API from the default package into a more reasonable spot? It sounds like you don't have access to the source code. I am not sure if the package is encoded into class files, so simply moving the API class might be worth a try. Otherwise, Java decompilers like JAD usually do a good job, so you could change the package name in the decompiled source and compile it again.