有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

jaxb反序列化XML以在Java中动态创建类

我有一组抽象类,如下所示:

abstract class A {
    public abstract B getB() {return this.b;}

    public abstract void setB(B b) {this.b = b;}
}

abstract class B {
    public abstract C getC() {return this.c;}

    public abstract void setC(C c) {this.c = c;}
}

abstract class C {
    private String foo;

    public String getFoo() {return this.foo;}

    public void setFoo(String foo) {this.foo = foo;}
}

在运行时,我使用ByteBuddy为这些类创建代理。我可以轻松地将这些代理类的对象序列化为XML。但是当我尝试反序列化XML时,JAXB抛出javax.xml.bind.UnmarshalException: Unable to create an instance of A,因为它无法创建抽象类的实例。我想向它展示如何在运行时创建这些实例,以便对它们进行反序列化(我有一个特殊的SpringBean,它可以做到这一点,所以我需要能够在定义创建逻辑的任何地方注入它),我查看了JAXB和Jackson,但找不到如何做到这一点

有办法吗?我不受任何序列化框架的约束,不过最好还是使用JAXB或Jackson


共 (1) 个答案

  1. # 1 楼答案

    我发现JAXB和Jackson都能做到这一点

    JAXB提供了两种解决方法:工厂方法和适配器

    1. 使用JAXB工厂方法,我需要创建一个负责对象创建的工厂:

      public class MyFactory {
          public static MyObject createMyObject() {
              return SomeMagic.createMyObject();
          }
      }
      

      然后我只需要用@XmlType注释标记我的抽象类:

      @XmlType(factoryClass = MyFactory.class, factoryMethod = "createMyObject")
      public abstract class MyObject {
           ...
      }
      
    2. 如果我想使用JAXB适配器,我需要创建JAXB可以从XML实例化和填充的Java类,然后我需要将这些类的对象转换为我需要的对象:

      public class MyAdapter extends XmlAdapter<MyAdapter.MyJaxbObject, MyObject> {
          @Override
          public MyObject unmarshal(MyJaxbObject src) throws Exception {
              MyObject tgt = SomeMagic.createMyObject();
              BeanUtils.copyProperties(tgt, src);
              return tgt;
          }
      
          @Override
          public MyObject marshal(MyObject src) throws Exception {
              MyJaxbObject tgt = new MyJaxbObject();
              BeanUtils.copyProperties(tgt, src);
              return tgt;
          }
      
          public static class MyJaxbObject {
             ...
          }
      } 
      

      然后我将用@XmlJavaAdapter注释标记我的抽象类:

      @XmlJavaAdapter(MyAdapter.class)
      public abstract class MyObject {
          ...
      }
      
    3. 使用Jackson,我可以为抽象类创建自定义反序列化程序

      public class MyObjectDeserializer extends StdDeserializer<MyObject> {
          public MyObjectDeserializer() {
              super(MyObject.class);
          }
      
          @Override
          public MyObject deserialize(JsonParser parser, DeserializationContext context) throws IOException {
              ObjectMapper mapper = (ObjectMapper) parser.getCodec();
              MyObject myObject = SomeMagic.createMyObject();
              return mapper.readerForUpdating(myObject).readValue(parser);
          }
      }
      

      在代码的后面部分,我需要注册反序列化程序:

      ObjectMapper mapper = new XmlMapper();
      SimpleModule module = new SimpleModule("module", new Version(1, 0, 0, null, null, null));
      module.addDeserializer(MyObject.class, new MyObjectDeserializer());
      mapper.registerModule(module);
      

    出于我的目的,我更喜欢Jackson自定义反序列化程序,因为:

    1. 我还需要在填充嵌套对象的字段之后,但在将这些对象传递给其他对象的setter之前,对这些对象执行其他操作(JAXB似乎不支持)
    2. 我可以在填充对象的字段时使用自定义逻辑(也可以通过适配器实现)
    3. 我可以自己创建反序列化程序,所以我可以使用依赖项注入来配置它们(工厂是静态的,适配器是由JAXB创建的)