Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 动态加载的pojo类的Jackson反序列化/类型引用_Java_Json_Jackson_Jsonschema2pojo - Fatal编程技术网

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,因为您事先不知道结构。正如您在这里发现的,这不适合类/类加载器抽象

见例


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

    • 在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()之前失败,那么您就会遇到另一个问题(我猜是类加载)

      使用泛型更好:

          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));
          }
      }