Jackson deserialisation / TypeReference用于动态加载的pojo类 [英] Jackson deserialisation/TypeReference for dynamically loaded pojo class
问题描述
我需要输入 JSON
输入Pojo实例,我使用的是 Jackson 2
库以及 readValue
方法可以使用typeReferencing反序列化:
I have a requirement to get JSON
input Pojo instance and I am using Jackson 2
library and below readValue
method could deserialise using typeReferencing :
POJO_ClassName p = mapper.readValue(new TypeReference< POJO_ClassName >() {});
但问题是因为 POJO
是在运行时动态创建和加载,如何获得 JSON
到 POJO
实例/对象,因为我没有完全限定上述语句的类(POJO_ClassName)名称?
But the problem is that as POJO
is created and loaded at runtime dynamically, how do I get JSON
to POJO
instance/object as I do not have fully qualified class (POJO_ClassName) name for above statement?
注意:我使用 jsonSchema2pojo
库生成 POJO
运行时的类。
Note: I use jsonSchema2pojo
library to generate POJO
classes at runtime.
这是代码片段,我用来生成 POJO
for $ code> JSON 在运行时
并尝试
Here is code snippet, I am using to generate POJO
for JSON
at runtime
and trying
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
,编译器会在找不到类时出错。
But as com.EnrichmentService.Thread72.EsRootDoc
has yet not been generated compiler would error to class not Found.
要点:
1)相同的Pojo类在运行时迭代生成但具有不同的属性,因为每次JSON输入都会更改。
1) Same Pojo classes generated at run time iteratively but with different properties as JSON input changes each time.
2)甚至尝试了
Object pojo = mapper.readValue(json,Class.forName(com.EnrichmentService.Thread72.EsRootDoc));因为class.forName不会替换现有的类!
2) Even tried Object pojo =mapper.readValue(json,Class.forName("com.EnrichmentService.Thread72.EsRootDoc")); as class.forName does not replace an existing class!
编辑8月23日 - 这是我的自定义类加载器:
Edit 24 Aug17 - Here is my custom class loader :
注意: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自定义类加载器作为替代方式是这样的:
I have tried using above TestClassLoader custom class loader as an alternative way is like this :
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.
提到旧答案@ 如何在java中正在运行的应用程序中替换类?
编辑2:24Aug17
遇到异常stackTrace就在这里: https: //pastebin.com/ckCu2uWx
推荐答案
你找到了,你只能使用 TypeReference
包含在编译时已知的类型(没有一些非常棘手的元编程)。
you have found, you can only use TypeReference
with types that are known at compile time (without some very tricky meta-programming).
但是,有很多替代重载 readValue
,不需要 TypeReference
,以允许像你这样的情况 TypeReference
是不切实际的。
However, there are lots of alternative overloads to readValue
which do not require a TypeReference
, to allow for cases like yours where TypeReference
is impractical.
我认为你可以使用 readValue(...,Class< T> valueType)
I think you can use readValue(... , Class<T> valueType)
如果您有这些后期编译类的特殊类加载器,那么您可以得到 Class
实例并将其传入,例如:
If you have a special Classloader for these late-compiled classes, then you can get a Class
instance from that and pass it in, for example:
ClassLoader dynamicallyCompiledPojoLoader = ...;
Class<?> pojoClass = dynamicallyCompiledPojoLoader.loadClass("...");
return mapper.readValue(..., pojoClass);
参见 com.fasterxml.jackson.databind.type.TypeFactory ,用于指定参数化泛型类型而不使用 TypeReference
See also com.fasterxml.jackson.databind.type.TypeFactory for specifying parameterised generic types without using TypeReference
您当前的例外( https://pastebin.com/ckCu2uWx )不是类加载器问题,但JSON模式不匹配问题。
Your current exception ( https://pastebin.com/ckCu2uWx ) is not a class loader issue, but a JSON schema mismatch issue.
异常消息的相关部分是:
The relevant part of the exception message is:
Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
...
through reference chain: com.EnrichmentService.Thread72.EsRootDoc["category"]->java.util.ArrayList[0]->com.EnrichmentService.Thread72.Category["crawler"])
所以杰克逊不高兴JSON中的crawler字段是一个对象,即以 {
开头,但Java属性crawler是一个ArrayList,即应该以<$开头 c $ c> [
So Jackson is unhappy that the "crawler" field in the JSON is an object, i.e. starts with "{
", but the Java property "crawler" is an ArrayList, i.e. should start with "[
"
我不知道为什么POJO结构 Thread72.Category
在这里是错误的,但它看起来不像是一个类加载器问题。
I don't know why the POJO structure of Thread72.Category
is wrong here, but it doesn't look like a classloader problem.
您已经说过1)POJO类结构因每个请求而异,2)您希望每次都为POJO使用相同的类名。
You have said that 1) the POJO class structure varies with each request and 2) you want to use the same classname for the POJO each time.
您需要为每个请求使用新的类加载器,因为类会被类加载器缓存。到目前为止您发布的代码表明您正在使用单个类加载器并希望在每个请求上加载类别类,这将无效。
You'll need to use a new Classloader for each request, as classes get cached by Classloaders. The code you have posted so far suggests that you are using a single classloader and hoping for a new load of the "Category" class on each request, which won't work.
你说过:
我需要每次为基于drools的elasticsearch文档重新索引工作生成新类,这个drools设置需要pojo /对象类型instances.thanks
I need to generate new classes each time for a drools based elasticsearch document re-indexing work and this drools setup needs pojo/Object type instances.thanks
...但我认为你应该考虑使用地图或类似输入到Drools而不是鉴于您事先并不知道结构,而不是基于反射的POJO。正如你在这里找到的那样,这不适合类/类加载器抽象。
... but I think you should look into using a Map or similar input to Drools rather than a reflection based POJO, given that you don't know the structure in advance. As you have found here, this is a poor fit for the class / classloader abstraction.
参见例如
- https:// groups .google.com / forum /#!topic / drools-usage / CbuSO-V-w_g
- 将Java POJO转换为Drools DRL,反之亦然
- < a href =https://groups.google.com/forum/#!topic/drools-usage/0BIXF3Tg5pw =nofollow noreferrer> https://groups.google.com/forum/#!topic/drools -usage / 0BIXF3Tg5pw
- https://groups.google.com/forum/#!topic/drools-usage/CbuSO-V-w_g
- Convert Java POJO to Drools DRL and vice versa
- https://groups.google.com/forum/#!topic/drools-usage/0BIXF3Tg5pw
这篇关于Jackson deserialisation / TypeReference用于动态加载的pojo类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!