JAXB 深入显出 - JAXB 教程 XML转Java对象深入(Unmarshaller)

Bertha 。 2022-04-12 04:10 326阅读 0赞

摘要: 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经过改造:

  1. package com.example.demo.lesson17;
  2. import java.io.Serializable;
  3. import javax.xml.bind.Unmarshaller;
  4. import javax.xml.bind.annotation.XmlAccessType;
  5. import javax.xml.bind.annotation.XmlAccessorType;
  6. import javax.xml.bind.annotation.XmlRootElement;
  7. @XmlRootElement(name= "Employe")
  8. @XmlAccessorType(XmlAccessType.FIELD)
  9. public class Employe implements Serializable{
  10. private static final long serialVersionUID = 1L;
  11. private String id;
  12. private String name;
  13. public String getId() {
  14. return id;
  15. }
  16. public void setId(String id) {
  17. this.id = id;
  18. }
  19. public String getName() {
  20. return name;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. void beforeUnmarshal(Unmarshaller unmarshaller, Object parent) {
  26. System.out.println("调用Unmarshaller之前");
  27. }
  28. void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
  29. System.out.println("调用Unmarshaller之后");
  30. }
  31. @Override
  32. public String toString() {
  33. return "Employee [id=" + id + ", name=" + name + "]";
  34. }
  35. }

测试一下:

  1. @Test
  2. public void test1() throws JAXBException {
  3. JAXBContext context = JAXBContext.newInstance(Employe.class);
  4. Unmarshaller unmarshaller = context.createUnmarshaller();
  5. String xmlStr = "<Employe><id>1504</id><name>Test</name></Employe>";
  6. Employe employe = (Employe)unmarshaller.unmarshal(new StringReader(xmlStr));
  7. System.out.println(employe);//Employee [id=1504, name=Test]
  8. }

结果:

  1. 调用Unmarshaller之前
  2. 调用Unmarshaller之后
  3. Employee [id=1504, name=Test]

这两个方法在某些场合可以起到自定义 Unmarshaller 的效果。

复杂XML转化

之前见到的XML都是一层结构,真实场景中的XML肯定复杂的多。但是对于特别复杂的XML结构,我不会深入,因为XML都是一级一级的结构,再复杂的XML也是多级拼接而成,于是正确的拆分XML便是反序列化中重要的一环。

  1. <employee id="17">
  2. <department>
  3. <id>101</id>
  4. <name>IT</name>
  5. </department>
  6. <firstName>Lokesh</firstName>
  7. <lastName>Gupta</lastName>
  8. </employee>

对于这个XML,需要把XML拆分成两部分:最外层的employe和嵌套的department。如果遇到XML中是属性的,在Java bean的字段上添加注解@XmlAttribute,需要名称不一样的,添加别名@XmlElement(name="FirstName")

Employee的部分重要代码:

  1. @XmlRootElement(name = "employee")
  2. @XmlAccessorType(XmlAccessType.FIELD)
  3. public class Employee {
  4. @XmlAttribute
  5. private Integer id;
  6. @XmlElement(name="FirstName")
  7. private String firstName;
  8. private String lastName;
  9. private Department department;
  10. // ignore setters/getters,toString
  11. }

Department的完整代码:

  1. package com.example.demo.lesson17;
  2. public class Department {
  3. public String id;
  4. public String name;
  5. @Override
  6. public String toString() {
  7. return "Department [id=" + id + ", name=" + name + "]";
  8. }
  9. }

因为比较简单,不需要任何注解,看起来好像和JAXB无关的Department。

测试一下:

  1. @Test
  2. public void test2() throws JAXBException {
  3. JAXBContext context = JAXBContext.newInstance(Employee.class);
  4. Unmarshaller unmarshaller = context.createUnmarshaller();
  5. String xmlStr = "<employee id='17'>\r\n" +
  6. " <department>\r\n" +
  7. " <id>101</id>\r\n" +
  8. " <name>IT</name>\r\n" +
  9. " </department>\r\n" +
  10. " <FirstName>Lokesh</FirstName>\r\n" +
  11. " <id>1</id>\r\n" +
  12. " <lastName>Gupta</lastName>\r\n" +
  13. "</employee>";
  14. Employee employee = (Employee)unmarshaller.unmarshal(new StringReader(xmlStr));
  15. System.out.println(employee);//Employee [id=17, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
  16. }

得到的结果:

  1. Employee [id=17, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]

所有的字段都反序列化成功了,不仅仅得到了Employee,还得到了Department数据。

有的XML显得更为复杂,像下面这种:

  1. <MUSEUMS>
  2. <MUSEUM children_allowed="false">
  3. <MUSEUM_NAME>Reina Sofia Museum</MUSEUM_NAME>
  4. <CITY>Madrid</CITY>
  5. <PERMANENT_EXHIBITION>
  6. <NAME>Permanent Exhibition - Reina Sofia Museum</NAME>
  7. <ARTIST>Picasso</ARTIST>
  8. <ARTIST>Dali</ARTIST>
  9. <ARTIST>Miro</ARTIST>
  10. <FROM>1900-01-01</FROM>
  11. <TO>2014-12-31</TO>
  12. </PERMANENT_EXHIBITION>
  13. </MUSEUM>
  14. <MUSEUM>
  15. <MUSEUM_NAME>Louvre Museum</MUSEUM_NAME>
  16. <CITY>Paris</CITY>
  17. <PERMANENT_EXHIBITION>
  18. <NAME>Permanent Exhibition - Louvre Museum</NAME>
  19. <ARTIST>Leonardo da Vinci</ARTIST>
  20. <ARTIST>Caravaggio</ARTIST>
  21. <ARTIST>Delacroix</ARTIST>
  22. </PERMANENT_EXHIBITION>
  23. </MUSEUM>
  24. <TOTAL>2</TOTAL>
  25. </MUSEUMS>

这种XML结构在业务场景更普遍,它们很长,看着很复杂,其实并没有想象的那么难。这个数据看着复杂,其实更多的是重复,既然都是一样的,那就需要巧用‘循环’了。而Java bean中的循环当然要考虑List,它里面包含的数据都是相同类型,结构必然一样,把上面这段XML拆分后,就得到了3个Java bean。

最外层的Java bean:

  1. @XmlRootElement(name = "MUSEUMS")
  2. @XmlAccessorType(XmlAccessType.FIELD)
  3. public class Museums {
  4. @XmlElement(name = "MUSEUM")
  5. List<Museum> museums;
  6. @XmlElement(name = "TOTAL")
  7. String total;
  8. // ignore setters/getters,toString
  9. }

接下来的Meseum:

  1. @XmlRootElement( name = "MUSEUM" )
  2. @XmlType( propOrder = { "name", "city", "special" } )
  3. @XmlAccessorType(XmlAccessType.FIELD)
  4. public class Museum {
  5. @XmlElement(name = "MUSEUM_NAME")
  6. String name;
  7. @XmlAttribute(name = "children_allowed", required=false)
  8. Boolean childrenAllowed;
  9. @XmlElement(name = "CITY")
  10. String city;
  11. @XmlElement(name = "PERMANENT_EXHIBITION")
  12. Exhibition special;
  13. // ignore setters/getters,toString
  14. }

接下来的一层:

  1. @XmlAccessorType(XmlAccessType.FIELD)
  2. public class Exhibition {
  3. @XmlElement(name = "NAME")
  4. String name;
  5. @XmlElement(name = "ARTIST")
  6. List<String> artist;
  7. @XmlElement(name = "FROM")
  8. String from;
  9. @XmlElement(name = "TO")
  10. String to;
  11. // ignore setters/getters,toString
  12. }

演示代码比较长:

  1. @Test
  2. public void test3() throws JAXBException {
  3. JAXBContext context = JAXBContext.newInstance(Museums.class);
  4. Unmarshaller unmarshaller = context.createUnmarshaller();
  5. String xmlStr = "<MUSEUMS>\r\n" +
  6. " <MUSEUM children_allowed=\"false\">\r\n" +
  7. " <MUSEUM_NAME>Reina Sofia Museum</MUSEUM_NAME>\r\n" +
  8. " <CITY>Madrid</CITY>\r\n" +
  9. " <PERMANENT_EXHIBITION>\r\n" +
  10. " <NAME>Permanent Exhibition - Reina Sofia Museum</NAME>\r\n" +
  11. " <ARTIST>Picasso</ARTIST>\r\n" +
  12. " <ARTIST>Dali</ARTIST>\r\n" +
  13. " <ARTIST>Miro</ARTIST>\r\n" +
  14. " <FROM>1900-01-01</FROM>\r\n" +
  15. " <TO>2014-12-31</TO>\r\n" +
  16. " </PERMANENT_EXHIBITION>\r\n" +
  17. " </MUSEUM>\r\n" +
  18. " <MUSEUM>\r\n" +
  19. " <MUSEUM_NAME>Louvre Museum</MUSEUM_NAME>\r\n" +
  20. " <CITY>Paris</CITY>\r\n" +
  21. " <PERMANENT_EXHIBITION>\r\n" +
  22. " <NAME>Permanent Exhibition - Louvre Museum</NAME>\r\n" +
  23. " <ARTIST>Leonardo da Vinci</ARTIST>\r\n" +
  24. " <ARTIST>Caravaggio</ARTIST>\r\n" +
  25. " <ARTIST>Delacroix</ARTIST>\r\n" +
  26. " </PERMANENT_EXHIBITION>\r\n" +
  27. " </MUSEUM>\r\n" +
  28. " <TOTAL>2</TOTAL>\r\n" +
  29. "</MUSEUMS>";
  30. Museums museums = (Museums)unmarshaller.unmarshal(new StringReader(xmlStr));
  31. System.out.println(museums);
  32. //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=2014-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]
  33. }

XML中所有的元素都被正确识别。

无论多么复杂的XML结构,都离不开这几种拼接形式,嵌套的越多,需要越多的Java对象与之对应。
对于一些需要特殊处理的数据,需要使用到适配器来私人订制。

完整代码

可以在GitHub找到完整代码。
本节代码均在该包下:package com.example.demo.lesson17;

下节预览

本节介绍了 JAXB 将复杂 XML 转化为Java对象。下一节开始,讲述JAXB对于JSON的支持场景。

发表评论

表情:
评论列表 (有 0 条评论,326人围观)

还没有评论,来说两句吧...

相关阅读