我想创建内部对象结构的XML表示形式。根据我的发现,JAXB2
看起来很有前途。我刚刚完成了一些教程(Link1,Link2),并且有一个对我来说很重要的问题。
我确实有两个类,POJO1
和POJO2
,具有相同的超类型AbstractPOJO
。所有这些都是使用项目lombok
生成的,我想获取XML文档中所有AbstractPOJO
的列表。这些类型可以为POJO1
或POJO2
。
我最终会希望得到类似的东西
<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属性?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
,并将XmlRootElement
和XmlAccessorType
添加到其实现POJO1
和POJO2
中。但是,然后我得到一个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}}。所以我有点卡住了。
将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);
}
}
}
。
但是,这是正确的方法吗?