这不是您问题的最终答案。但我希望这可以为您提供继续前进的方向。请注意,此方向会在运行时修改字节码指令,并可能导致崩溃和失败。
您可以使用javassist,它是一个字节码操纵器。请查看他们的official site 了解更多信息。
需要注意的两个重要事项
-
在 Java 中,多个类加载器可以共存,并且每个类加载器都创建自己的命名空间。不同的类加载器可以加载不同的类名相同的类文件
-
JVM 不允许动态重新加载类。一旦类加载器加载了一个类,它就不能在运行时重新加载该类的修改版本。因此,您不能在 JVM 加载类之后更改它的定义。但是,JPDA(Java 平台调试器架构)提供的重新加载类的能力有限
所以你可以通过两种不同的方式实现你想要的。
-
在运行时创建字节码,编写类,使用自定义类加载器从编写的类创建你的 pojo。 javassist 可以帮你解决这个问题,但这对我来说太复杂了。
-
使用javassist 修改现有类并使用反射设置值。
对于选项 2,更简单的一个,您可以通过以下方式实现这一目标。
- 在你的类路径中添加
javassist。如果您使用的是 maven,请在 pom.xml 中添加以下依赖项。
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
- 创建一个您需要使用的虚拟空 pojo 类。让我们称之为
Pojo。
package com.test;
public class Pojo {
//Nothing in the source file.
}
- 修改类主体以添加来自
HashMap 的字段。这是我如何使用您提供的地图的示例。
Map<String, String> map = new HashMap<String, String>();
map.put("firstname", "John");
map.put("lastname", "Doe");
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("com.test.Pojo");
// Used for non-primitive data types. If primitive, use CtClass.<inttype, floattype, etc..>
CtClass strClass = ClassPool.getDefault().get("java.lang.String");
//Iterate and add all the fields as per the keys in the map
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
CtField field = new CtField(strClass, key, cc);
field.setModifiers(Modifier.PUBLIC);
cc.addField(field);
}
// Instantiate from the updated class
Class<Pojo> clazz = cc.toClass();
Pojo newInstance = clazz.newInstance();
//Use the map again to set the values using reflection.
iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
newInstance.getClass().getField(key).set(newInstance, map.get(key));
}
-
newInstance 是 Pojo 的实例,但是根据映射的键添加字段并根据映射中的值进行设置。使用 jackson ObjectMapper 打印 newInstance 的简单测试会产生此结果。
ObjectMapper objMapper = new ObjectMapper();
String writeValueAsString = objMapper.writeValueAsString(newInstance);
System.out.println(writeValueAsString);
{"firstname":"John","lastname":"Doe"}
希望这会有所帮助。
编辑
如果你想添加get/set方法,你可以在javassist中使用CtMethod创建方法。但是,您只能使用反射来访问它们,因为这些方法是在运行时添加的。