是否可以在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);
}
}
如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;
}
}
}
}
为了说明这一点,我创建了两个类,它们都属于默认包:
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”编译
公共类Order扩展java.lang.Object {
私人客户客户;
公共秩序(客户);
码:
0:加载_0
1:调用特殊#10; //方法java / lang / Object。“” :()V
4:aload_0
5:aload_1
6:普特菲尔德#13;//字段客户:LCustomer;
9:返回
公共客户getCustomer();
码:
0:加载_0
1:getfield#13;//字段客户:LCustomer;
4:阿伦
public void setCustomer(Customer);
码:
0:加载_0
1:aload_1
2:putfield#13;//字段客户:LCustomer;
5:返回
}
这是重新映射Order
后 的列表(com.mycompany
用作默认软件包):
> javap -private -c命令
从“ Order.java”编译
公共类com.mycompany.Order扩展了com.mycompany.java.lang.Object {
私人com.mycompany.Customer客户;
公共com.mycompany.Order(com.mycompany.Customer);
码:
0:加载_0
1:调用特殊#30; //方法“ com.mycompany.java/lang/Object"."":()V
4:aload_0
5:aload_1
6:普特菲尔德#32;//字段客户:Lcom.mycompany.Customer;
9:返回
公共com.mycompany.Customer getCustomer();
码:
0:加载_0
1:getfield#32;//字段客户:Lcom.mycompany.Customer;
4:阿伦
公共无效setCustomer(com.mycompany.Customer);
码:
0:加载_0
1:aload_1
2:putfield#32;//字段客户:Lcom.mycompany.Customer;
5:返回
}
如您所见,重新映射更改了Order
对的所有引用com.mycompany.Order
和对的所有Customer
引用com.mycompany.Customer
。
该类加载器将必须加载以下任一类的所有类:
问题内容: 我知道,Java没有预处理器,因此Java中有些东西或多或少是不可能的。 真的 没有 办法在循环中用动态名称填充这些数组吗?我想要类似的东西: 代替 还是有可以使用的古怪技巧? 问题答案: 我会那样做: 如果要使用该方法:
我需要下载shapely,但我总是出错。 起初,我尝试使用: 它不起作用,所以我在网上搜索它,有人告诉我去这里下载文件:https://www.lfd.uci.edu/~gohlke/pythonlibs/#shapely我下载了名为Shapely1.6.4.post1-cp37-cp37mwin_amd64.whl的文件,因为我的窗口是64位,这是最新的一个。我又试了一次,但没有成功。我在这个问
我得到了(超过)两个Api POSTendpoint。每一个都需要一个json作为参数。但是当我在两个endpoint参数类中使用相同的类名负载时,Swagger就不起作用了。当我改变其中的一个,例如从有效载荷到有效载荷1时,它就不起作用了。当然,我在包装类中设置了正确的名称空间,以便它找到负载。但我希望每次都使用相同的名称“有效载荷”。如何使用相同的类名负载?在这两种情况下,我都可以保留json
我有OSGI bundle(比方说A),它依赖于非OSGI库(比方说B)。B正在使用class.ForName加载一个类(库A中的ClassA是库B中的ClassB类型)。我已经包装了库B,使其成为osgi捆绑包,并导入了库A中所需的包,但我无法使用class.forname加载该类。请注意,库B是第三方库,我没有任何控制这一点。 下面是我创建的支持OSGI的库B的清单文件- manifest-v
问题内容: 在我的Java应用程序中,我使用第三方库。 但是,我发现有些奇怪,有一些嵌套的程序包,有些类的名称可能与程序包的名称相同。 恐怕我不清楚。这是一个例子: 包 在“ com.xx.a”内部有一个名为“ a”的类。 因此,如果我想将此类称为“ a” … 我写: 然后,IDE将认为我的意思是软件包“ com.xx.a.a”。 那我就不能打电话了。 我想知道为什么? 顺便说一句,图书馆提供者似
问题内容: 我查找了语法并搜索了api,但仍然对该过程感到困惑。我还搜索了Stackoverflow。加载类并从中动态创建对象的正确方法是什么?换句话说,我希望用户指定要创建的对象类型,然后创建该类型的对象。我不需要菜单,因为我希望他们能够选择当前目录中的任何类。 问题答案: 假设该类具有无参数构造函数,则最简单的方法是- 参考-java.lang.Class