• JAXB实现JavaBean与XML相互转换(详尽)


    本文针对使用JAXB实现JavaBean与XML之间的相互转换,基本涵盖所有场景。

    概念

    JAXB是Java Architecture for XML Binding的缩写。可以将一个Java对象转变成为XML格式,反之亦然。 
        我们把对象与关系数据库之间的映射称为ORM,其实也可以把对象与XML之间的映射称为OXM(Object XML Mapping)。原来JAXB是Java EE的一部分,在JDK1.6中,SUN将其放到了Java SE中,这也是SUN的一贯做法。JDK1.6中自带的这个JAXB版本是2.0,比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要作绑定的类和属性等,这就极大简化了开发的工作量。

    常见的注解说明

    JAXBContext类:是应用的入口,用于管理XML/Java绑定信息。
    Marshaller接口:将Java对象序列化为XML数据。
    Unmarshaller接口:将XML数据反序列化为Java对象。
    @XmlRootElement:将Java类或枚举类型映射到XML元素,用在Java类上,用于标注该类是xml的一个根节点。
    @XmlElement:将Java类的一个属性映射到与属性同名的一个XML元素。通常与@XmlTransient搭配使用。
    @XmlTransient:通常与 @XmlElement 须搭配使用的。@XmlElement用在属性上,用于指定生成xml的节点名,@XmlTransient用在对应的getter方法上,起到关联的作用。
    @XmlElementWrapper :对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。通常配合XmlElement一起使用,XmlElementWrapper指定数组名,XmlElement指定生成xml的节点名。
    @XmlElementRef:用在类属性的getter方法上(即该属性是一个JavaBean),并且该属性是某些子类的父类,起到引用的作用。同时标注得有@XmlElementRef的类属性,其子类上需要使用@XmlRootElement标注,否则转换异常,提示找不到具体的引用实现。另外,转换时,需要将其子类的class一起传递到JAXBContext上下文中,否则也无法转换。
    @XmlAccessorOrder:控制JAXB 绑定类中属性和字段的排序。

    @XmlType:将Java类或枚举类型映射到XML模式类型
    @XmlAccessorType(XmlAccessType.FIELD) :控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标 注)字段到XML。还有XmlAccessType.PROPERTY和XmlAccessType.NONE。
    @XmlJavaTypeAdapter:使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。
    @XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。

    1.工具方法

    1. public class XmlBeanUtils {
    2. /**
    3. * Java Bean 转 Xml
    4. *
    5. * @param bean - Java Bean
    6. * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
    7. * @return - xml
    8. */
    9. public static String beanToXml(Object bean, Class... inheritClazz) {
    10. try {
    11. JAXBContext context = initContext(bean.getClass(), inheritClazz);
    12. Marshaller marshaller = context.createMarshaller();
    13. // 格式化xml
    14. marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    15. marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
    16. // 是否去掉xml头
    17. marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
    18. StringWriter writer = new StringWriter();
    19. marshaller.marshal(bean, writer);
    20. return writer.toString();
    21. } catch (JAXBException e) {
    22. e.printStackTrace();
    23. }
    24. return null;
    25. }
    26. /**
    27. * Xml 转 Java Bean
    28. *
    29. * @param xml - xml
    30. * @param beanClazz - Java Bean Class
    31. * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
    32. * @return - bean
    33. */
    34. public static Object xmlToBean(String xml, Class beanClazz, Class... inheritClazz) {
    35. try {
    36. JAXBContext context = initContext(beanClazz, inheritClazz);
    37. Unmarshaller um = context.createUnmarshaller();
    38. StringReader sr = new StringReader(xml);
    39. return um.unmarshal(sr);
    40. } catch (JAXBException e) {
    41. e.printStackTrace();
    42. }
    43. return null;
    44. }
    45. /**
    46. * 初始化JAXBContext
    47. *
    48. * @param mainClazz - 序列化或反序列化Class
    49. * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
    50. * @return - JAXBContext
    51. */
    52. private static JAXBContext initContext(Class mainClazz, Class... inheritClazz) throws JAXBException {
    53. JAXBContext context;
    54. if (inheritClazz != null) {
    55. Class[] clazzArr = new Class[inheritClazz.length + 1];
    56. clazzArr[0] = mainClazz;
    57. System.arraycopy(inheritClazz, 0, clazzArr, 1, clazzArr.length - 1);
    58. context = JAXBContext.newInstance(clazzArr);
    59. } else {
    60. context = JAXBContext.newInstance(mainClazz);
    61. }
    62. return context;
    63. }
    64. }

    2.应用实例

    1.1.普通对象的转换

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.XmlElement;
    6. import javax.xml.bind.annotation.XmlRootElement;
    7. import javax.xml.bind.annotation.XmlTransient;
    8. /**
    9. * 简单JavaBean与XML转换
    10. */
    11. public class SimpleTest {
    12. public static void main(String[] args) {
    13. Cat cat = new Cat("猫咪", "爱吃鱼");
    14. String xml = XmlBeanUtils.beanToXml(cat);
    15. System.out.println("bean->xml = " + xml);
    16. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Cat.class));
    17. }
    18. @ToString
    19. @NoArgsConstructor
    20. @AllArgsConstructor
    21. @Setter
    22. @XmlRootElement(name = "Cat")
    23. static class Cat {
    24. @XmlElement(name = "CatName")
    25. private String name;
    26. @XmlElement(name = "Hobby")
    27. private String hobby;
    28. @XmlTransient
    29. public String getName() {
    30. return name;
    31. }
    32. @XmlTransient
    33. public String getHobby() {
    34. return hobby;
    35. }
    36. }
    37. }

    1.2.有继承关系的对象转换

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.XmlElement;
    6. import javax.xml.bind.annotation.XmlRootElement;
    7. import javax.xml.bind.annotation.XmlTransient;
    8. /**
    9. * 继承关系JavaBean与XML转换
    10. */
    11. public class InheritBeanTest {
    12. public static void main(String[] args) {
    13. // 具有继承关系,使用Cat 或 Animal 接收都可以。
    14. // Cat cat = new Cat("猫咪", "爱吃鱼");
    15. Animal cat = new Cat("猫咪", "爱吃鱼");
    16. String xml = XmlBeanUtils.beanToXml(cat);
    17. System.out.println("bean->xml = " + xml);
    18. // 此处不能使用父类Animal来接收,因为无法推断具体的实现类是哪个,必须使用具体的实现类Cat来接收
    19. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Cat.class));
    20. }
    21. @Setter
    22. abstract static class Animal {
    23. // 不建议定义属性,因为从XML->Bean时,父类属性会丢失
    24. }
    25. @ToString
    26. @NoArgsConstructor
    27. @AllArgsConstructor
    28. @Setter
    29. @XmlRootElement(name = "Cat")
    30. static class Cat extends Animal {
    31. @XmlElement(name = "CatName")
    32. private String name;
    33. @XmlElement(name = "Hobby")
    34. private String hobby;
    35. @XmlTransient
    36. public String getName() {
    37. return name;
    38. }
    39. @XmlTransient
    40. public String getHobby() {
    41. return hobby;
    42. }
    43. }
    44. }

    1.3.嵌套的类属性是普通对象的转换

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.XmlElement;
    6. import javax.xml.bind.annotation.XmlRootElement;
    7. import javax.xml.bind.annotation.XmlTransient;
    8. /**
    9. * 有嵌套关系的JavaBean与XML转换
    10. */
    11. public class NestBeanTest {
    12. public static void main(String[] args) {
    13. Cat cat = new Cat("猫咪", "爱吃鱼");
    14. Person person = new Person("貂蝉", 18, cat);
    15. String xml = XmlBeanUtils.beanToXml(person);
    16. System.out.println("bean->xml = " + xml);
    17. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class));
    18. }
    19. @ToString
    20. @NoArgsConstructor
    21. @AllArgsConstructor
    22. @Setter
    23. @XmlRootElement(name = "Person")
    24. static class Person {
    25. @XmlElement(name = "UserName")
    26. private String name;
    27. @XmlElement(name = "Age")
    28. private int age;
    29. // 嵌套的JavaBean
    30. @XmlElement(name = "Pet")
    31. private Cat cat;
    32. @XmlTransient
    33. public String getName() {
    34. return name;
    35. }
    36. @XmlTransient
    37. public int getAge() {
    38. return age;
    39. }
    40. @XmlTransient
    41. public Cat getCat() {
    42. return cat;
    43. }
    44. }
    45. @ToString
    46. @NoArgsConstructor
    47. @AllArgsConstructor
    48. @Setter
    49. @XmlRootElement(name = "Cat")
    50. static class Cat {
    51. @XmlElement(name = "CatName")
    52. private String name;
    53. @XmlElement(name = "Hobby")
    54. private String hobby;
    55. @XmlTransient
    56. public String getName() {
    57. return name;
    58. }
    59. @XmlTransient
    60. public String getHobby() {
    61. return hobby;
    62. }
    63. }
    64. }

    1.4.嵌套类属性是的集合(数组)普通对象的转换

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.XmlElement;
    6. import javax.xml.bind.annotation.XmlElementWrapper;
    7. import javax.xml.bind.annotation.XmlRootElement;
    8. import javax.xml.bind.annotation.XmlTransient;
    9. import java.util.ArrayList;
    10. import java.util.List;
    11. /**
    12. * 有嵌套关系的集合JavaBean与XML转换
    13. */
    14. public class NestListBeanTest {
    15. public static void main(String[] args) {
    16. List cats = new ArrayList<>();
    17. cats.add(new Cat("大猫咪", "爱吃大鱼"));
    18. cats.add(new Cat("小猫咪", "爱吃小鱼"));
    19. Person person = new Person("貂蝉", 18, cats);
    20. String xml = XmlBeanUtils.beanToXml(person);
    21. System.out.println("bean->xml = " + xml);
    22. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class));
    23. }
    24. @ToString
    25. @NoArgsConstructor
    26. @AllArgsConstructor
    27. @Setter
    28. @XmlRootElement(name = "Person")
    29. static class Person {
    30. @XmlElement(name = "UserName")
    31. private String name;
    32. @XmlElement(name = "Age")
    33. private int age;
    34. // 嵌套的集合JavaBean:XmlElementWrapper指定集合数组XML节点名,XmlElement指定具体的节点名
    35. @XmlElementWrapper(name = "PetArray")
    36. @XmlElement(name = "Pet")
    37. private List cats;
    38. @XmlTransient
    39. public String getName() {
    40. return name;
    41. }
    42. @XmlTransient
    43. public int getAge() {
    44. return age;
    45. }
    46. @XmlTransient
    47. public List getCats() {
    48. return cats;
    49. }
    50. }
    51. @ToString
    52. @NoArgsConstructor
    53. @AllArgsConstructor
    54. @Setter
    55. @XmlRootElement(name = "Cat")
    56. static class Cat {
    57. @XmlElement(name = "CatName")
    58. private String name;
    59. @XmlElement(name = "Hobby")
    60. private String hobby;
    61. @XmlTransient
    62. public String getName() {
    63. return name;
    64. }
    65. @XmlTransient
    66. public String getHobby() {
    67. return hobby;
    68. }
    69. }
    70. }

    1.5.嵌套的类属性是继承关系对象的转换

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.XmlElement;
    6. import javax.xml.bind.annotation.XmlElementRef;
    7. import javax.xml.bind.annotation.XmlRootElement;
    8. import javax.xml.bind.annotation.XmlTransient;
    9. /**
    10. * 有嵌套且有继承关系的JavaBean与XML转换
    11. */
    12. public class NestInheritBeanTest {
    13. public static void main(String[] args) {
    14. // 此处使用Animal或Cat来接收都是可以的,因为已经创建了具体的Bean
    15. Animal cat = new Cat("猫咪", "爱吃鱼");
    16. Person person = new Person("貂蝉", 18, cat);
    17. // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
    18. String xml = XmlBeanUtils.beanToXml(person, Cat.class);
    19. System.out.println("bean->xml = " + xml);
    20. // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
    21. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class, Cat.class));
    22. }
    23. @ToString
    24. @NoArgsConstructor
    25. @AllArgsConstructor
    26. @Setter
    27. @XmlRootElement(name = "Person")
    28. static class Person {
    29. @XmlElement(name = "UserName")
    30. private String name;
    31. @XmlElement(name = "Age")
    32. private int age;
    33. // 嵌套的JavaBean,且是父类,此处不能使用@XmlElement标注,否则会报错,
    34. // 原因是父类不知道具体的子类实现,需要在子类中使用@XmlRootElement标注具体的实现
    35. private Animal animal;
    36. @XmlTransient
    37. public String getName() {
    38. return name;
    39. }
    40. @XmlTransient
    41. public int getAge() {
    42. return age;
    43. }
    44. // 必须使用@XmlElementRef来标注父类,起到引用的作用
    45. @XmlElementRef
    46. public Animal getAnimal() {
    47. return animal;
    48. }
    49. }
    50. @Setter
    51. abstract static class Animal {
    52. }
    53. @ToString
    54. @NoArgsConstructor
    55. @AllArgsConstructor
    56. @Setter
    57. @XmlRootElement(name = "Cat")
    58. static class Cat extends Animal {
    59. @XmlElement(name = "CatName")
    60. private String name;
    61. @XmlElement(name = "Hobby")
    62. private String hobby;
    63. @XmlTransient
    64. public String getName() {
    65. return name;
    66. }
    67. @XmlTransient
    68. public String getHobby() {
    69. return hobby;
    70. }
    71. }
    72. }

    1.6.嵌套的类属性是集合(数组)继承关系对象的转换

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.*;
    6. import java.util.ArrayList;
    7. import java.util.List;
    8. /**
    9. * 有嵌套且有继承关系的集合JavaBean与XML转换
    10. */
    11. public class NestInheritListBeanTest {
    12. public static void main(String[] args) {
    13. // 此处使用Animal来接,属于List泛型知识,此处不再赘述
    14. List animals = new ArrayList<>();
    15. animals.add(new Cat("大猫咪", "爱吃大鱼"));
    16. animals.add(new Cat("小猫咪", "爱吃小鱼"));
    17. Person person = new Person("貂蝉", 18, animals);
    18. // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
    19. String xml = XmlBeanUtils.beanToXml(person, Cat.class);
    20. System.out.println("bean->xml = " + xml);
    21. // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
    22. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class, Cat.class));
    23. }
    24. @ToString
    25. @NoArgsConstructor
    26. @AllArgsConstructor
    27. @Setter
    28. @XmlRootElement(name = "Person")
    29. static class Person {
    30. @XmlElement(name = "UserName")
    31. private String name;
    32. @XmlElement(name = "Age")
    33. private int age;
    34. // 嵌套的JavaBean,且是父类,此处不能使用@XmlElement标注,否则会报错,
    35. // 原因是父类不知道具体的子类实现,需要在子类中使用@XmlRootElement标注具体的实现
    36. private List animals;
    37. @XmlTransient
    38. public String getName() {
    39. return name;
    40. }
    41. @XmlTransient
    42. public int getAge() {
    43. return age;
    44. }
    45. // 必须使用@XmlElementRef来标注父类,起到引用的作用
    46. // 必须使用@XmlElementWrapper指定集合数组XML节点名
    47. @XmlElementRef
    48. @XmlElementWrapper(name = "PetArray")
    49. public List getAnimals() {
    50. return animals;
    51. }
    52. }
    53. @Setter
    54. abstract static class Animal {
    55. }
    56. @ToString
    57. @NoArgsConstructor
    58. @AllArgsConstructor
    59. @Setter
    60. @XmlRootElement(name = "Cat")
    61. static class Cat extends Animal {
    62. @XmlElement(name = "CatName")
    63. private String name;
    64. @XmlElement(name = "Hobby")
    65. private String hobby;
    66. @XmlTransient
    67. public String getName() {
    68. return name;
    69. }
    70. @XmlTransient
    71. public String getHobby() {
    72. return hobby;
    73. }
    74. }
    75. }

    1.7.有继承关系且父类有属性的对象的转换

    (不推荐使用,XML->Bean转换时父类属性会丢失

    1. import lombok.AllArgsConstructor;
    2. import lombok.NoArgsConstructor;
    3. import lombok.Setter;
    4. import lombok.ToString;
    5. import javax.xml.bind.annotation.XmlElement;
    6. import javax.xml.bind.annotation.XmlElementRef;
    7. import javax.xml.bind.annotation.XmlRootElement;
    8. import javax.xml.bind.annotation.XmlTransient;
    9. /**
    10. * 有嵌套且有继承关系的JavaBean与XML转换
    11. * 且父类中定义了属性,XML->Bean,父类属性会丢失(除非必要,不要再父类中定义属性)
    12. */
    13. public class NoSupportNestInheritBeanTest {
    14. public static void main(String[] args) {
    15. // 此处使用Animal或Cat来接收都是可以的,因为已经创建了具体的Bean
    16. Cat cat = new Cat("猫咪", "爱吃鱼");
    17. cat.setCountry("中国");
    18. Person person = new Person("貂蝉", 18, cat);
    19. // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
    20. String xml = XmlBeanUtils.beanToXml(person, Cat.class);
    21. System.out.println("bean->xml = " + xml);
    22. // 转换时需要将Person中Animal类属性的实现类Cat.class传入。否则无法无法转换,因为不清楚具体的实现。
    23. System.out.println("xml->bean = " + XmlBeanUtils.xmlToBean(xml, Person.class, Cat.class));
    24. }
    25. @ToString
    26. @NoArgsConstructor
    27. @AllArgsConstructor
    28. @Setter
    29. @XmlRootElement(name = "Person")
    30. static class Person {
    31. @XmlElement(name = "UserName")
    32. private String name;
    33. @XmlElement(name = "Age")
    34. private int age;
    35. // 嵌套的JavaBean,且是父类,此处不能使用@XmlElement标注,否则会报错,
    36. // 原因是父类不知道具体的子类实现,需要在子类中使用@XmlRootElement标注具体的实现
    37. private Animal animal;
    38. @XmlTransient
    39. public String getName() {
    40. return name;
    41. }
    42. @XmlTransient
    43. public int getAge() {
    44. return age;
    45. }
    46. // 必须使用@XmlElementRef来标注父类,起到引用的作用
    47. @XmlElementRef
    48. public Animal getAnimal() {
    49. return animal;
    50. }
    51. }
    52. @Setter
    53. abstract static class Animal {
    54. @XmlElement(name = "Country")
    55. private String country;
    56. @XmlTransient
    57. public String getCountry() {
    58. return country;
    59. }
    60. }
    61. @ToString
    62. @NoArgsConstructor
    63. @AllArgsConstructor
    64. @Setter
    65. @XmlRootElement(name = "Cat")
    66. static class Cat extends Animal {
    67. @XmlElement(name = "CatName")
    68. private String name;
    69. @XmlElement(name = "Hobby")
    70. private String hobby;
    71. @XmlTransient
    72. public String getName() {
    73. return name;
    74. }
    75. @XmlTransient
    76. public String getHobby() {
    77. return hobby;
    78. }
    79. }
    80. }

  • 相关阅读:
    用python实现基本数据结构【03/4】
    曼哈顿距离和-打印菱形
    基于lstm DNN的多变量单变量时间预测项目-完整数据+代码
    LintCode 3208:String splitting字符串处理入门题
    HOW TO EASILY CREATE BARPLOTS WITH ERROR BARS IN R
    微信自动批量添加好友的方法
    34.线程的生命周期【20220812】
    JCJC-基于剪贴板的碎片信息收集工具
    常用建模工具
    Vue+Elementui历史导航标签实现
  • 原文地址:https://blog.csdn.net/gengzhy/article/details/127564536