将XML反序列化为Java

时间:2017-04-10 13:33:46

标签: java jaxb jackson deserialization

我有一组这样的抽象类:

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,因为它无法创建抽象类的实例。我想向它展示如何在运行时创建这些实例以便反序列化它们(我有一个特殊的Spring bean,它可以实现它 - 所以我需要能够在我定义创建逻辑的任何地方注入它)我看了JAXB和Jackson ,但找不到怎么做。

有办法吗?我不受任何序列化框架的约束,但最好留在JAXB或Jackson。

1 个答案:

答案 0 :(得分:0)

我发现JAXB和杰克逊都能做到。

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);
    
  4. 出于我的目的,我更喜欢Jackson自定义反序列化器,因为:

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