文章21 | 阅读 7882 | 点赞0
摘要: JAXB 作为JDK的一部分,能便捷地将Java对象与XML进行相互转换,本教程从实际案例出发来讲解JAXB 2 的那些事儿。完整版目录
上一节主要是 One.java,本节每一小节都是不同的Java bean,展示不同的 Java 对象编组成 XML 。
默认的 XML Root Element name 是 Java 对象的 类名 首字母小写。
@Test public void test() throws JAXBException { // 首先创建 JAXBContext JAXBContext context = JAXBContext.newInstance(Two.class); // 初始化 Marshaller Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 创建简单的 Java bean Two o = new Two(); o.setName("Test two"); // 将结果输出到控制台 marshaller.marshal(o, System.out); }
其实最关键的就在这个 @XmlRootElement
,指定name
,然后最终的Root name就是这里指定的值。
@XmlRootElement(name = "Second") public class Two { private String name; // setters,getters }
输出结果就是上面指定的 name
。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Second>
<name>Test two</name>
</Second>
在不指定确定值时,XML 子元素名称是Java 属性的名称。
@Test public void test3() throws JAXBException { JAXBContext context = JAXBContext.newInstance(Three.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Three t = new Three(); t.setName("Test three"); marshaller.marshal(t, System.out); }
通过指定@XmlElement
的 name
,改变XML 元素名称。
@XmlRootElement public class Three { private String name; public String getName() { return name; } @XmlElement(name = "Naming") public void setName(String name) { this.name = name; } }
输出结果就是上面指定的 name
。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<three>
<Naming>Test three</Naming>
</three>
默认情况下,Java 属性是XML 子元素。
@Test public void test4() throws JAXBException { JAXBContext context = JAXBContext.newInstance(Four.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Four f = new Four(); f.setId("1004"); f.setName("Test three"); marshaller.marshal(f, System.out); }
通过指定@XmlAttribute
来限制输出为 XML 属性,同样地,可以指定 @XmlAttribute(name = "identity")
改变XML 属性名称。
@XmlRootElement public class Four { private String id; private String name; public String getId() { return id; } @XmlAttribute public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
输出结果id
就是一个属性,没有指定name
,所以还是输出为XML 元素。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<four id="1004">
<name>Test three</name>
</four>
对于有层级结构的XML,可以通过Java bean嵌套来实现。
@Test public void test5() throws JAXBException { JAXBContext context = JAXBContext.newInstance(Five.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Five f = new Five(); Four four = new Four(); four.setName("This is 4"); f.setName("Test 5"); f.setFour(four); marshaller.marshal(f, System.out); }
引用上一级的Four.java
,就可以输出第二级 XML 结构。
@XmlRootElement public class Five { private String name; private Four four; // setters,getters }
输出的 XML 是有两级层级结构的,更复杂的结构将在接下来的章节中介绍。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<five>
<four>
<name>This is 4</name>
</four>
<name>Test 5</name>
</five>
在使用 Java 构造器构造Java对象,编组 XML 时,需要注意得手动设置空的构造器。
@Test public void test6() throws JAXBException { JAXBContext context = JAXBContext.newInstance(Six.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Six six = new Six("1006", "Test6", "Some descrptions"); marshaller.marshal(six, System.out); }
如果要覆盖构造器,需要注意空构造器不能省。
@XmlRootElement(name = "Six") public class Six { private String code; private String name; private String desc; public Six() {} public Six(String code, String name, String desc) { super(); this.code = code; this.name = name; this.desc = desc; } // setters,getters }
生成的XML并不是按照自己书写的顺序。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Six>
<code>1006</code>
<desc>Some descrptions</desc>
<name>Test6</name>
</Six>
默认情况下,Jaxb编组出来的xml中的字段顺序是随机的。@XmlAccessorOrder
可以控制输出顺序,它有两个值,默认为UNDEFINED(无序),XmlAccessorOrder.ALPHABETICAL是指按属性的字母顺序排序。
需要指定时可以在类名上加@XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
或者@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
@Test public void test7() throws JAXBException { JAXBContext context = JAXBContext.newInstance(Seven.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Seven s = new Seven(); s.setCode("1007"); s.setName("Test name"); s.setAge(22); s.setDesc("The desc"); s.setSlary(21.45); marshaller.marshal(s, System.out); }
如果要自主定义顺序,需要使用到 @XmlType
,其中的 propOrder
是一个数组,可以指定顺序。
@XmlRootElement @XmlType(propOrder = {"code", "name", "age", "desc"}) public class Seven { private String code; private String name; private String desc; private int age; private double slary; // setters,getters @XmlTransient public void setSlary(double slary) { this.slary = slary; } }
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<seven>
<code>1007</code>
<name>Test name</name>
<age>22</age>
<desc>The desc</desc>
</seven>
对于没有 @XmlTransient
标注过的属性,必须出现在 @XmlType
的propOrder列表中。否则 会报错com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions 属性slary已存在, 但未在 @XmlType.propOrder 中指定
JAXB默认会处理 Java 的 Field 和 setters/getters 方法,有时候,我喜欢将各种注解标注在 Java 字段上,于是可能会发生如下异常。
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions 类的两个属性具有相同名称 "code"
这是因为我在字段上标注过一个 JAXB 注解。
@XmlElement private String code;
这样 JAXB 在处理时,发现同名的属性,就会报错,像我这样喜欢将注解放置在字段上的话,需要指定一个@XmlAccessorType
,将其值指定为 Field 就可以了。
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Eight { @XmlElement private String code; private String name; public String getCode() { return code; } // @XmlElement public void setCode(String code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
当然,这时也不能同时在 setters
方法上添加注解,否则还是会出错。注释掉的代码如果放开的话,会报同样的错。因为@XmlElement
是最底层的注解,会覆盖在类上标注的@XmlAccessorType(XmlAccessType.FIELD)
。
比如有时候,Java对象有很多属性,我只希望将其中的几个编组为XML,在其他属性或者 setters
方法上标注@XmlTransient
显得有些笨拙,就可以先设置@XmlAccessorType(XmlAccessType.NONE)
,然后在需要编组的字段上标注@XmlElement
。
@Test public void test9() throws JAXBException { JAXBContext context = JAXBContext.newInstance(Nine.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Nine n = new Nine(); n.setCode("1009"); n.setName("Test case"); n.setAge(22); n.setDesc("The desc"); n.setSlary(29.99); marshaller.marshal(n, System.out); }
标注@XmlAccessorType(XmlAccessType.NONE)
,暗示所有的属性不能编组为XML。
@XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class Nine { @XmlElement(name = "id") private String code; private String name; private String desc; private int age; private double slary; // setters,getters }
注解@XmlElement(name = "id")
覆盖了类上的设置。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nine>
<id>1009</id>
</nine>
可以在GitHub找到完整代码。
本节代码均在该包下:package com.example.demo.lesson10;
下一节主要介绍更为复杂的 XML 结构,主要是多层嵌套的结构。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://jiangchao.blog.csdn.net/article/details/82795134
内容来源于网络,如有侵权,请联系作者删除!