Java 动态加载的pojo类的Jackson反序列化/类型引用
我需要获取Java 动态加载的pojo类的Jackson反序列化/类型引用,java,json,jackson,jsonschema2pojo,Java,Json,Jackson,Jsonschema2pojo,我需要获取JSON输入Pojo实例,我正在使用Jackson 2库,下面的readValue方法可以使用类型引用进行反序列化: POJO_ClassName p = mapper.readValue(new TypeReference< POJO_ClassName >() {}); 但由于com.EnrichmentService.Thread72.EsRootDoc尚未生成,编译器将错误为找不到类 要点: 1) 在运行时以迭代方式生成相同的Pojo类,但每次JSON输入更改时具
JSON
输入Pojo实例,我正在使用Jackson 2
库,下面的readValue
方法可以使用类型引用进行反序列化:
POJO_ClassName p = mapper.readValue(new TypeReference< POJO_ClassName >() {});
但由于com.EnrichmentService.Thread72.EsRootDoc
尚未生成,编译器将错误为找不到类
要点:
1) 在运行时以迭代方式生成相同的Pojo类,但每次JSON输入更改时具有不同的属性
2) 甚至试过
Object pojo=mapper.readValue(json,Class.forName(“com.EnrichmentService.Thread72.EsRootDoc”);as class.forName不会替换现有类
编辑2017年8月24日-这是我的自定义类加载器:
注意:索引器是在运行时加载动态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);
}
}
引用了一个旧的答案@
Edit2:2017年8月24日
stackTrace面临的异常是:您发现,您只能对编译时已知的类型使用
TypeReference
(没有一些非常棘手的元编程)
然而,readValue
有许多替代重载,它们不需要TypeReference
,以允许像您这样的情况下TypeReference
是不切实际的
我想你可以用
如果您有一个用于这些后期编译类的特殊类加载器,那么您可以从中获取一个类
实例并将其传入,例如:
ClassLoader dynamicallyCompiledPojoLoader = ...;
Class<?> pojoClass = dynamicallyCompiledPojoLoader.loadClass("...");
return mapper.readValue(..., pojoClass);
final String ConcurrentHashMap<String, Class> dynamicClasses = new ConcurrentHashMap();
Object doInThreadOne(String json, String className) {
return mapper.readObject(json, dynamicClasses.get(className))
void doInAnotherThread(String className) {
dynamicClasses.put(className, reload(className));
}
因此,Jackson不满意JSON中的“crawler”字段是一个对象,即以“{
”开头,但Java属性“crawler”是一个数组列表,即应以“[
开头”
我不知道为什么Thread72.Category
的POJO结构在这里是错误的,但它看起来不像是类加载器问题
在注释POJO类随每个请求而更改后更新
您已经说过1)POJO类结构随每个请求而变化,2)您希望每次对POJO使用相同的类名
看
当类被类加载器缓存时,您需要为每个请求使用一个新的类加载器。到目前为止,您发布的代码表明您正在使用一个类加载器,并希望在每个请求上加载一个新的“Category”类,这是行不通的
你说过:
我每次都需要为基于drools的elasticsearch文档重新编制索引工作生成新类,而drools设置需要pojo/对象类型实例。谢谢
…但是我认为您应该考虑使用映射或类似的输入到Drools,而不是基于反射的POJO,因为您事先不知道结构。正如您在这里发现的,这不适合类/类加载器抽象
见例
- 在comile时间创建并编译类(例如,使用maven和jaxb) 或
- 你可以这样做:
String className = "com.EnrichmentService.Thread72.EsRootDoc"; Class<?> clazz = Class.forName(className); Object object = clazz.getConstructor().newInstance(); Object p = mapper.readValue(json, object.getClass());
String className=“com.EnrichmentService.Thread72.EsRootDoc”; Class clazz=Class.forName(className); Object Object=clazz.getConstructor().newInstance(); objectp=mapper.readValue(json,Object.getClass());
如果该代码在mapper.readValue()之前失败,那么您就会遇到另一个问题(我猜是类加载)
使用泛型更好:
- Imo有两种方法可以解决这个问题:
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);
}
String className=“com.EnrichmentService.Thread72.EsRootDoc”;
Class clazz=Class.forName(className);
//不能以静态方式使用动态创建的类,只是为了
//说明重点
//com.EnrichmentService.Thread72.EsRootDoc p=
//getObjectFromMessageString(json,clazz);
objectp=getObjectFromString(json,clazz);
公共静态T getObjectFromString(字符串json,类clazz){
返回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);
}
}
}
导入java.io.File;
导入java.io.IOException;
导入java.io.InputStream;
导入java.nio.charset.StandardCharset;
导入java.nio.file.Files;
导入javax.tools.JavaCompiler;
导入javax.tools.ToolProvider;
导入com.fasterxml.jackson.core.JsonParseException;
导入com.fasterxml.jackson.databind.JsonMappingException;
导入com.fasterxml.jackson.databind.ObjectMapper;
公共类JackonCustomClassTest{
公共静态字符串CLASS_NAME=“EsRootDoc”;
公共静态字符串包_NAME=“com.EnrichmentService.Thread72”;
公共静态字符串规范名称=包名称+“+”+类名称;
公共静态void main(字符串args[])引发异常{
JackonCustomClassTest mtc=新的JackonCustomClassTest();
c类=空;
字符串源=null;
//第一次编译类
source=“package”+package\u NAME+“public class”+class\u NAME+“{public”+class\u NAME+”(){};公共字符串toString(){return\“NAME:不存在\“+\”-className:\“+getClass().getCanonicalName();};”;
c=mtc.compileClass(规范名称,源);
System.out.println(“类测试:+c.newInstance().toString());
//第二次编译类
source=“package”+package\u NAME+“public class”+class\u NAME+“{private String NAME;public”+class\u 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(规范名称,源);
System.out.println(“类测试:+c.newInstance().toString());
mtc.runJackson(c);
}
私有void runJackson(类clazz)抛出JsonParseException、JsonMappingException、IOException{
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);
}
}
}
final String ConcurrentHashMap<String, Class> dynamicClasses = new ConcurrentHashMap();
Object doInThreadOne(String json, String className) {
return mapper.readObject(json, dynamicClasses.get(className))
void doInAnotherThread(String className) {
dynamicClasses.put(className, reload(className));
}
static final String className = "com.EnrichmentService.Thread72.EsRootDoc";
final String Map<String, Class> dynamicClasses = new HashMap();
Object doInThreadOne(String json) {
synchronized(className) {
return mapper.readObject(json, dynamicClasses.get(className))
}
void doInAnotherThread(String className) {
synchronized(className) {
dynamicClasses.put(className, reload(className));
}
}