Jackson deserialisation/TypeReference用于动态加载的pojo类

Kim*_*chy 12 java json jackson jsonschema2pojo

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

POJO_ClassName p = mapper.readValue(new TypeReference< POJO_ClassName >() {});
Run Code Online (Sandbox Code Playgroud)

但问题是,作为POJO被创建并加载在运行时动态,我怎么JSONPOJO实例/对象,因为我没有对上述说法完全限定类(POJO_ClassName)的名字吗?

注意:我使用jsonSchema2pojoPOJO在运行时生成类.

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

  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
Run Code Online (Sandbox Code Playgroud)

但是由于com.EnrichmentService.Thread72.EsRootDoc尚未生成编译器,因此找不到类的错误.

要点:

1)迭代地在运行时生成相同的Pojo类,但每次都改变JSON输入时具有不同的属性.

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

编辑8月17日 - 这是我的自定义类加载器:

注意: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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

我已经尝试使用上面的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.
Run Code Online (Sandbox Code Playgroud)

提到了一个旧的答案@ 如何在java中运行的应用程序中替换类?

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

Ric*_*ich 3

您发现,您只能使用TypeReference编译时已知的类型(没有一些非常棘手的元编程)。

但是,有许多替代重载readValue不需要TypeReference, 来允许像您这样TypeReference不切实际的情况。

我想你可以使用readValue(... , Class<T> valueType)

如果您有一个用于这些后期编译类的特殊类加载器,那么您可以Class从中获取一个实例并将其传递进去,例如:

ClassLoader dynamicallyCompiledPojoLoader = ...;
Class<?> pojoClass = dynamicallyCompiledPojoLoader.loadClass("...");

return mapper.readValue(..., pojoClass);
Run Code Online (Sandbox Code Playgroud)

另请参阅com.fasterxml.jackson.databind.type.TypeFactory以指定参数化泛型类型而不使用TypeReference

在“Edit2:24Aug17 遇到异常 stackTrace is here”之后更新

您当前的异常(https://pastebin.com/ckCu2uWx)不是类加载器问题,而是 JSON 架构不匹配问题。

异常消息的相关部分是:

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"])
Run Code Online (Sandbox Code Playgroud)

所以 Jackson 不高兴的是 JSON 中的“crawler”字段是一个对象,即以“ {”开头,但是 Java 属性“crawler”是一个 ArrayList,即应该以“ [”开头

我不知道为什么这里的POJO结构Thread72.Category是错误的,但是看起来不像是类加载器的问题。

注释后更新 POJO 类随每个请求而变化

您说过 1) POJO 类结构随每个请求而变化,2) 您希望每次对 POJO 使用相同的类名。

请参阅Java - 如何加载同一类的不同版本?

您需要为每个请求使用新的类加载器,因为类由类加载器缓存。到目前为止您发布的代码表明您正在使用单个类加载器,并希望在每个请求上重新加载“类别”类,但这是行不通的。

你曾说过:

我需要每次为基于 drools 的 elasticsearch 文档重新索引工作生成新类,并且此 drools 设置需要 pojo/Object 类型实例。谢谢

...但我认为您应该考虑使用 Map 或类似的 Drools 输入,而不是基于反射的 POJO,因为您事先不知道结构。正如您在这里所发现的,这不太适合类/类加载器抽象。

参见例如