gpt4 book ai didi

java - 动态加载的 pojo 类的 Jackson 反序列化/TypeReference

转载 作者:搜寻专家 更新时间:2023-10-30 21:31:38 46 4
gpt4 key购买 nike

我需要获取 JSON 输入 Pojo 实例,我正在使用 Jackson 2 库,下面的 readValue 方法可以使用 typeReferencing 反序列化:

POJO_ClassName p = mapper.readValue(new TypeReference< POJO_ClassName >() {});

但问题是,由于 POJO 是在运行时动态创建和加载的,我如何将 JSON 获取到 POJO 实例/对象我没有上述声明的完全限定类 (POJO_ClassName) 名称?

注意:我使用 jsonSchema2pojo 库在运行时生成 POJO 类。

这是代码片段,我用它在运行时为 JSON 生成 POJO并尝试

  String classPath="com.EnrichmentService.Thread72"; 
String classLocation = System.getProperty("user.dir")
+ "/src/main/java"; JCodeModel codeModel = new JCodeModel();

final RuleFactory ruleFactory = new RuleFactory(config,
new Jackson2Annotator(config), new SchemaStore());

final SchemaMapper mapperSchema = new SchemaMapper(ruleFactory,
new SchemaGenerator());

mapperSchema.generate(codeModel, "EsRootDoc",classPath, json);

codeModel.build(new File(classLocation)); // generates pojo classes

// Till above jsonSchema2Pojo pojo generation all Good !!
// EsRootDoc instance is needed for further drools drl validations.

com.EnrichmentService.Thread72.EsRootDoc p = mapper.readValue(new TypeReference<com.EnrichmentService.Thread72.EsRootDoc>() {});
// see alternative way as well in my 24Aug17 edit at the end of this question

但由于 com.EnrichmentService.Thread72.EsRootDoc 尚未生成,编译器将错误为未找到类。

要点:

1) 在运行时迭代生成相同的 Pojo 类,但随着 JSON 输入每次更改而具有不同的属性。

2) 甚至尝试过对象 pojo =mapper.readValue(json,Class.forName("com.EnrichmentService.Thread72.EsRootDoc"));因为 class.forName 不会替换现有的类!

Edit 24 Aug17 - 这是我的自定义类加载器:

注意:Indexer是运行时加载动态EsRootDoc/POJO类的类。

 static class TestClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("com.EnrichmentService.Thread72.EsRootDoc")) {
try {
InputStream is = Indexer.class.getClassLoader().getResourceAsStream("com/EnrichmentService/Thread72/EsRootDoc.class");
byte[] buf = new byte[is.available()];
int len = is.read(buf);

Class<?> c=defineClass(name, buf, 0, len);
resolveClass(c);
return c;


} catch (IOException e) {
throw new ClassNotFoundException("", e);
}
}
return getParent().loadClass(name);
}
}

我试过使用上面的 TestClassLoader 自定义类加载器作为替代方法是这样的:

Class cls = new      TestClassLoader().loadClass("com.EnrichmentService.Thread72.EsRootDoc");
Object obj = cls.newInstance();
cls.getMethod("getCrawlerSource").invoke(obj);
p=mapper.readValue(json, cls); // but here i am getting the same deserialization exception as earlier.

引用旧答案@ How to replace classes in a running application in java ?

Edit2:24Aug17 stackTrace 面临的异常在这里:https://pastebin.com/ckCu2uWx

最佳答案

我有两种方法可以解决这个问题:

  1. 在编译时创建和编译类(例如使用 maven 和 jaxb)

  1. 你做这样的事情:

    String className = "com.EnrichmentService.Thread72.EsRootDoc";
    Class<?> clazz = Class.forName(className);
    Object object = clazz.getConstructor().newInstance();
    Object p = mapper.readValue(json, object.getClass());

如果该代码在 mapper.readValue() 之前失败,您将遇到另一个问题(我猜是类加载)。

更好的是使用泛型:

    String className = "com.EnrichmentService.Thread72.EsRootDoc";
Class<?> clazz = Class.forName(className);
// cannot use dynamically created classes in a static way, just to
// show the point
// com.EnrichmentService.Thread72.EsRootDoc p =
// getObjectFromMessageString(json, clazz);
Object p = getObjectFromString(json, clazz);

public static <T> T getObjectFromString(String json, Class<T> clazz) {
return mapper.readValue(json, clazz);
}

编辑:

我写了一些示例代码,在运行时编译一个类,然后尝试转换为所述编译类的对象。输出如我所料:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JackonCustomClassTest {
public static String CLASS_NAME = "EsRootDoc";
public static String PACKAGE_NAME = "com.EnrichmentService.Thread72";
public static String CANONICAL_NAME = PACKAGE_NAME + "." + CLASS_NAME;

public static void main(String args[]) throws Exception {
JackonCustomClassTest mtc = new JackonCustomClassTest();
Class<?> c = null;
String source = null;
// compile class for the first time
source = "package "+PACKAGE_NAME+"; public class "+CLASS_NAME+" { public "+CLASS_NAME+"() { }; public String toString() { return \"Name: not existing\" + \" - className: \" + getClass().getCanonicalName(); }; }";
c = mtc.compileClass(CANONICAL_NAME, source);

System.out.println("class test: " + c.newInstance().toString());

// compile class for the second time
source = "package "+PACKAGE_NAME+"; public class "+CLASS_NAME+" { private String name; public "+CLASS_NAME+"() { }; public String getName() { return name; }; public void setName(String name) { this.name = name; }; public String toString() { return \"Name: \" + name + \" - className: \" + getClass().getCanonicalName(); }; }";
c = mtc.compileClass(CANONICAL_NAME, source);

System.out.println("class test: " + c.newInstance().toString());

mtc.runJackson(c);
}

private void runJackson(Class<?> clazz) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper m = new ObjectMapper();
String string = "{ \"name\": \"asdf\" }";
Object o = m.readValue(string, clazz);
System.out.println("result of conversion: " + o); // Should print "Name: asdf"
}

public Class<?> compileClass(String fullyQualifiedClassName, String source) throws Exception {
// Save source in .java file.
File root = new java.io.File( "./target/test-classes/" );
File sourceFile = new File(root, fullyQualifiedClassName.replace(".", "/") + ".java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));

// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());

// Load and instantiate compiled class.
// URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
// Class<?> cls = Class.forName(fullyQualifiedClassName, true, classLoader);
Class<?> cls = new TestClassLoader().loadClass(fullyQualifiedClassName);
return cls;
}

static class TestClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith(PACKAGE_NAME)) {
try {
InputStream is = this.getClass().getClassLoader()
.getResourceAsStream(name.replace(".", "/") + ".class");
byte[] buf = new byte[is.available()];
int len = is.read(buf);

Class<?> c = defineClass(name, buf, 0, len);
resolveClass(c);
return c;

} catch (IOException e) {
throw new ClassNotFoundException("", e);
}
}
return getParent().loadClass(name);
}
}
}

编辑 2:

更新代码以尝试您的 TestClassLoader 类 - 仍然获得该类的正确(更新)版本。

关于java - 动态加载的 pojo 类的 Jackson 反序列化/TypeReference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45518549/

46 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com