摘要:JAXB 作为JDK的一部分,能便捷地将Java对象与XML进行相互转换,本教程从实际案例出发来讲解JAXB 2 的那些事儿。完整版目录
前情回顾
上一节以简单介绍了 UnMarshaller 的过程,主要介绍了多种数据源如何处理。这一节将深入介绍XML数据转换为JAVA对象,将涉及更加复杂的XML结构。
Unmarshaller Callback
在JAXB反序列化时,有两个方法可以自定义一些行为,它们有固定的形式:
void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {}
void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {}
上一节中的Employe经过改造:
package com.example.demo.lesson17;import java.io.Serializable;import javax.xml.bind.Unmarshaller;import javax.xml.bind.annotation.XmlAccessType;import javax.xml.bind.annotation.XmlAccessorType;import javax.xml.bind.annotation.XmlRootElement;@XmlRootElement(name= "Employe")@XmlAccessorType(XmlAccessType.FIELD)public class Employe implements Serializable{private static final long serialVersionUID = 1L;private String id;private String name;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {System.out.println("调用Unmarshaller之前");}void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {System.out.println("调用Unmarshaller之后");}@Overridepublic String toString() {return "Employee [id=" + id + ", name=" + name + "]";}}
测试一下:
@Testpublic void test1() throws JAXBException {JAXBContext context = JAXBContext.newInstance(Employe.class);Unmarshaller unmarshaller = context.createUnmarshaller();String xmlStr = "<Employe><id>1504</id><name>Test</name></Employe>";Employe employe = (Employe)unmarshaller.unmarshal(new StringReader(xmlStr));System.out.println(employe);//Employee [id=1504, name=Test]}
结果:
调用Unmarshaller之前调用Unmarshaller之后Employee [id=1504, name=Test]
这两个方法在某些场合可以起到自定义 Unmarshaller 的效果。
复杂XML转化
之前见到的XML都是一层结构,真实场景中的XML肯定复杂的多。但是对于特别复杂的XML结构,我不会深入,因为XML都是一级一级的结构,再复杂的XML也是多级拼接而成,于是正确的拆分XML便是反序列化中重要的一环。
<employee id="17"><department><id>101</id><name>IT</name></department><firstName>Lokesh</firstName><lastName>Gupta</lastName></employee>
对于这个XML,需要把XML拆分成两部分:最外层的employe和嵌套的department。如果遇到XML中是属性的,在Java bean的字段上添加注解@XmlAttribute
,需要名称不一样的,添加别名@XmlElement(name="FirstName")
。
Employee的部分重要代码:
@XmlRootElement(name = "employee")@XmlAccessorType(XmlAccessType.FIELD)public class Employee {@XmlAttributeprivate Integer id;@XmlElement(name="FirstName")private String firstName;private String lastName;private Department department;// ignore setters/getters,toString}
Department的完整代码:
package com.example.demo.lesson17;public class Department {public String id;public String name;@Overridepublic String toString() {return "Department [id=" + id + ", name=" + name + "]";}}
因为比较简单,不需要任何注解,看起来好像和JAXB无关的Department。
测试一下:
@Testpublic void test2() throws JAXBException {JAXBContext context = JAXBContext.newInstance(Employee.class);Unmarshaller unmarshaller = context.createUnmarshaller();String xmlStr = "<employee id='17'>\r\n" + " <department>\r\n" + " <id>101</id>\r\n" + " <name>IT</name>\r\n" + " </department>\r\n" + " <FirstName>Lokesh</FirstName>\r\n" + " <id>1</id>\r\n" + " <lastName>Gupta</lastName>\r\n" + "</employee>";Employee employee = (Employee)unmarshaller.unmarshal(new StringReader(xmlStr));System.out.println(employee);//Employee [id=17, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]}
得到的结果:
Employee [id=17, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
所有的字段都反序列化成功了,不仅仅得到了Employee,还得到了Department数据。
有的XML显得更为复杂,像下面这种:
<MUSEUMS><MUSEUM children_allowed="false"><MUSEUM_NAME>Reina Sofia Museum</MUSEUM_NAME><CITY>Madrid</CITY><PERMANENT_EXHIBITION><NAME>Permanent Exhibition - Reina Sofia Museum</NAME><ARTIST>Picasso</ARTIST><ARTIST>Dali</ARTIST><ARTIST>Miro</ARTIST><FROM>1900-01-01</FROM><TO>-12-31</TO></PERMANENT_EXHIBITION></MUSEUM><MUSEUM><MUSEUM_NAME>Louvre Museum</MUSEUM_NAME><CITY>Paris</CITY><PERMANENT_EXHIBITION><NAME>Permanent Exhibition - Louvre Museum</NAME><ARTIST>Leonardo da Vinci</ARTIST><ARTIST>Caravaggio</ARTIST><ARTIST>Delacroix</ARTIST></PERMANENT_EXHIBITION></MUSEUM><TOTAL>2</TOTAL></MUSEUMS>
这种XML结构在业务场景更普遍,它们很长,看着很复杂,其实并没有想象的那么难。这个数据看着复杂,其实更多的是重复,既然都是一样的,那就需要巧用‘循环’了。而Java bean中的循环当然要考虑List,它里面包含的数据都是相同类型,结构必然一样,把上面这段XML拆分后,就得到了3个Java bean。
最外层的Java bean:
@XmlRootElement(name = "MUSEUMS")@XmlAccessorType(XmlAccessType.FIELD)public class Museums {@XmlElement(name = "MUSEUM")List<Museum> museums;@XmlElement(name = "TOTAL")String total;// ignore setters/getters,toString}
接下来的Meseum:
@XmlRootElement( name = "MUSEUM" )@XmlType( propOrder = {"name", "city", "special" } )@XmlAccessorType(XmlAccessType.FIELD)public class Museum {@XmlElement(name = "MUSEUM_NAME")String name;@XmlAttribute(name = "children_allowed", required=false)Boolean childrenAllowed;@XmlElement(name = "CITY")String city;@XmlElement(name = "PERMANENT_EXHIBITION")Exhibition special;// ignore setters/getters,toString}
接下来的一层:
@XmlAccessorType(XmlAccessType.FIELD)public class Exhibition {@XmlElement(name = "NAME")String name;@XmlElement(name = "ARTIST")List<String> artist;@XmlElement(name = "FROM")String from;@XmlElement(name = "TO")String to;// ignore setters/getters,toString}
演示代码比较长:
@Testpublic void test3() throws JAXBException {JAXBContext context = JAXBContext.newInstance(Museums.class);Unmarshaller unmarshaller = context.createUnmarshaller();String xmlStr = "<MUSEUMS>\r\n" + " <MUSEUM children_allowed=\"false\">\r\n" + " <MUSEUM_NAME>Reina Sofia Museum</MUSEUM_NAME>\r\n" + " <CITY>Madrid</CITY>\r\n" + " <PERMANENT_EXHIBITION>\r\n" + "<NAME>Permanent Exhibition - Reina Sofia Museum</NAME>\r\n" + "<ARTIST>Picasso</ARTIST>\r\n" + "<ARTIST>Dali</ARTIST>\r\n" + "<ARTIST>Miro</ARTIST>\r\n" + "<FROM>1900-01-01</FROM>\r\n" + "<TO>-12-31</TO>\r\n" + " </PERMANENT_EXHIBITION>\r\n" + " </MUSEUM>\r\n" + " <MUSEUM>\r\n" + " <MUSEUM_NAME>Louvre Museum</MUSEUM_NAME>\r\n" + " <CITY>Paris</CITY>\r\n" + " <PERMANENT_EXHIBITION>\r\n" + "<NAME>Permanent Exhibition - Louvre Museum</NAME>\r\n" + "<ARTIST>Leonardo da Vinci</ARTIST>\r\n" + "<ARTIST>Caravaggio</ARTIST>\r\n" + "<ARTIST>Delacroix</ARTIST>\r\n" + " </PERMANENT_EXHIBITION>\r\n" + " </MUSEUM>\r\n" + " <TOTAL>2</TOTAL>\r\n" + "</MUSEUMS>";Museums museums = (Museums)unmarshaller.unmarshal(new StringReader(xmlStr));System.out.println(museums);//Museums [museums=[Museum [name=Reina Sofia Museum, childrenAllowed=false, city=Madrid, special=Exhibition [name=Permanent Exhibition - Reina Sofia Museum, artist=[Picasso, Dali, Miro], from=1900-01-01, to=-12-31]], Museum [name=Louvre Museum, childrenAllowed=null, city=Paris, special=Exhibition [name=Permanent Exhibition - Louvre Museum, artist=[Leonardo da Vinci, Caravaggio, Delacroix], from=null, to=null]]], total=2]}
XML中所有的元素都被正确识别。
无论多么复杂的XML结构,都离不开这几种拼接形式,嵌套的越多,需要越多的Java对象与之对应。
对于一些需要特殊处理的数据,需要使用到适配器来私人订制。
完整代码
可以在GitHub找到完整代码。
本节代码均在该包下:package com.example.demo.lesson17;
下节预览
本节介绍了 JAXB 将复杂 XML 转化为Java对象。下一节开始,讲述JAXB对于JSON的支持场景。
如果觉得《JAXB 深入显出 - JAXB 教程 XML转Java对象深入(Unmarshaller)》对你有帮助,请点赞、收藏,并留下你的观点哦!