JAXB2:Lombok的继承和类型属性

时间:2019-06-25 16:46:18

标签: java xml inheritance jaxb lombok

我想创建内部对象结构的XML表示形式。根据我的发现,JAXB2看起来很有前途。我刚刚完成了一些教程(Link1Link2),并且有一个对我来说很重要的问题。

我确实有两个类,POJO1POJO2,具有相同的超类型AbstractPOJO。所有这些都是使用项目lombok生成的,我想获取XML文档中所有AbstractPOJO的列表。这些类型可以为POJO1POJO2

我最终会希望得到类似的东西

<model>
  <pojos>
    <pojo1 name="pojo1name" type="POJO1">
      <Foo>1</Foo>
      <Bar>2.0</Bar>
    </pojo1>
    <pojo2 name="pojo2name" type="POJO2">
      <Foo>1</Foo>
      <Baz>"name"</Baz>
    </pojo2>
  <pojos>
</model>

我的问题:

  • 如何将列表名称从AbstractPOJO更改为POJOs
  • 如何向AbstractPOJO列表中的每个项目添加带有类名称的type属性?

MWE

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.w3c.dom.Document;

public class Test {

    public static void main(String[] args) throws FileNotFoundException, JAXBException, ParserConfigurationException, TransformerException {

        Foo foo = new Foo(1);

        POJO1 p1 = new POJO1();
        p1.setName("pojo1name");
        p1.setFoo(foo);
        p1.setBar(new Bar(2.0));

        POJO2 p2 = new POJO2();
        p2.setName("pojo2name");
        p2.setFoo(foo);
        p2.setBaz(new Baz("name"));

        Memory mem = new Memory();
        mem.add(p1);
        mem.add(p2);

        // JAXB object
        Object jaxbElement = mem;

        File file = new File("./memory.xml");
        FileOutputStream fop = new FileOutputStream(file);

        // create JAXB context
        JAXBContext context = JAXBContext.newInstance(jaxbElement.getClass());

        // Creating the Document object
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.newDocument();

        // Marshaling the User object into a Document object
        Marshaller m = context.createMarshaller();
        m.marshal(jaxbElement, document);

        // writing the Document object to console
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();

        // set the properties for a formatted output - if false the output will be on one single line
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(fop);
        transformer.transform(source, result);
    }

    @Data
    public static class AbstractPOJO {
        private String name;
        private Foo foo;
    }

    @Data
    @EqualsAndHashCode(callSuper=true)
    public static class POJO1 extends AbstractPOJO {
        private Bar bar;
    }

    @Data
    @EqualsAndHashCode(callSuper=true)
    public static class POJO2 extends AbstractPOJO {
        private Baz baz;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Foo {
        private int id;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Bar {
        private double val;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Baz {
        private String name;
    }

    @Data
    public static class Memory {

        private Collection<AbstractPOJO> list;

        public void add(AbstractPOJO v){
            if (this.list == null){this.list = new ArrayList<>();}
            list.add(v);
        }
    }
}

由于我仍处于陡峭的学习曲线中,因此我没有在示例中包含任何JAXB注释。


更新

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.w3c.dom.Document;

public class Test {

    public static void main(String[] args) throws FileNotFoundException, JAXBException, ParserConfigurationException, TransformerException {

        Foo foo = new Foo(1);

        POJO1 p1 = new POJO1();
        p1.setName("pojo1name");
        p1.setFoo(foo);
        p1.setBar(new Bar(2.0));

        POJO2 p2 = new POJO2();
        p2.setName("pojo2name");
        p2.setFoo(foo);
        p2.setBaz(new Baz("name"));

        Memory mem = new Memory();
        mem.add(p1);
        mem.add(p2);

        // JAXB object
        Object jaxbElement = mem;

        File file = new File("./memory.xml");
        FileOutputStream fop = new FileOutputStream(file);

        // create JAXB context
        JAXBContext context = JAXBContext.newInstance(jaxbElement.getClass());

        // Creating the Document object
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.newDocument();

        // Marshaling the User object into a Document object
        Marshaller m = context.createMarshaller();
        m.marshal(jaxbElement, document);

        // writing the Document object to console
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();

        // set the properties for a formatted output - if false the output will be on one single line
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(fop);
        transformer.transform(source, result);
    }

    @Data
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class AbstractPOJO {

        @XmlAttribute
        private String name;
        private Foo foo;
    }

    @Data
    @EqualsAndHashCode(callSuper=true)
    //@XmlRootElement(name = "pojo1")
    public static class POJO1 extends AbstractPOJO {
        private Bar bar;
    }

    @Data
    @EqualsAndHashCode(callSuper=true)
    //@XmlRootElement(name = "pojo2")
    public static class POJO2 extends AbstractPOJO {
        private Baz baz;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Foo {
        private int id;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Bar {
        private double val;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Baz {
        private String name;
    }

    @Data
    @XmlRootElement(name="Memory")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Memory {

        @XmlElementWrapper(name ="POJOs")
        @XmlElement(type=AbstractPOJO.class, name="POJO")
        private Collection<AbstractPOJO> list;

        public void add(AbstractPOJO v){
            if (this.list == null){this.list = new ArrayList<>();}
            list.add(v);
        }
    }
}

因此,我添加了一些JAXB注释以查看得到的结果。结果是

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Memory>
  <POJOs>
    <POJO name="pojo1name">
      <foo>
        <id>1</id>
      </foo>
    </POJO>
    <POJO name="pojo2name">
      <foo>
        <id>1</id>
      </foo>
    </POJO>
  </POJOs>
</Memory>

因此,虽然有所进展,但仍然存在一些问题:

  • 如何获取类型属性,例如<POJO name="pojo1name" type="POJO1">
  • 当前可见的信息仅是抽象超类AbstractPOJO中的信息。如何在其中获取实际的实现属性?

我尝试制作AbstractPOJO XmlTransient,并将XmlRootElementXmlAccessorType添加到其实现POJO1POJO2中。但是,然后我得到一个SAXException2: javax.xml.bind.JAXBException: Weder class Test$POJO1 noch eine der zugehörigen Superklassen ist diesem Kontext bekannt.。松散翻译:{{1​​}}我可以将Neither class POJO1 nor one of its superclasses is known to this context.添加到@XmlSeeAlso(POJO1.class),但是随后我遇到Memory的相同错误,并且似乎无法在{{ 1}}。所以我有点卡住了。


更新2-知道了吗?

POJO2添加到XmlSeeAlso

@XmlSeeAlso({POJO1.class,POJO2.class})

产生

Memory

here中的import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Collection; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.XmlTransient; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import org.w3c.dom.Document; public class Test { public static void main(String[] args) throws FileNotFoundException, JAXBException, ParserConfigurationException, TransformerException { Foo foo = new Foo(1); POJO1 p1 = new POJO1(); p1.setName("pojo1name"); p1.setFoo(foo); p1.setBar(new Bar(2.0)); POJO2 p2 = new POJO2(); p2.setName("pojo2name"); p2.setFoo(foo); p2.setBaz(new Baz("name")); Memory mem = new Memory(); mem.add(p1); mem.add(p2); // JAXB object Object jaxbElement = mem; File file = new File("./memory.xml"); FileOutputStream fop = new FileOutputStream(file); // create JAXB context JAXBContext context = JAXBContext.newInstance(jaxbElement.getClass()); // Creating the Document object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.newDocument(); // Marshaling the User object into a Document object Marshaller m = context.createMarshaller(); m.marshal(jaxbElement, document); // writing the Document object to console TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); // set the properties for a formatted output - if false the output will be on one single line transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); DOMSource source = new DOMSource(document); StreamResult result = new StreamResult(fop); transformer.transform(source, result); } @Data @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) //@XmlTransient public static class AbstractPOJO { @XmlAttribute private String name; private Foo foo; } @Data @EqualsAndHashCode(callSuper=true) @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public static class POJO1 extends AbstractPOJO { private Bar bar; } @Data @EqualsAndHashCode(callSuper=true) @XmlTransient public static class POJO2 extends AbstractPOJO { private Baz baz; } @Data @NoArgsConstructor @AllArgsConstructor public static class Foo { private int id; } @Data @NoArgsConstructor @AllArgsConstructor public static class Bar { private double val; } @Data @NoArgsConstructor @AllArgsConstructor public static class Baz { private String name; } @Data @XmlRootElement(name="Memory") @XmlAccessorType(XmlAccessType.FIELD) @XmlSeeAlso({POJO1.class,POJO2.class}) public static class Memory { @XmlElementWrapper(name ="POJOs") @XmlElement(type=AbstractPOJO.class, name="POJO") private Collection<AbstractPOJO> list; public void add(AbstractPOJO v){ if (this.list == null){this.list = new ArrayList<>();} list.add(v); } } }

但是,这是正确的方法吗?

0 个答案:

没有答案