• JAXB常用注解详解


    一、简介

    JAXB(Java Architecture for XML Binding)是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。从另外一方面讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。

     

    二、示例

    Person.java

    package com.harara.jaxb.test1.entity;
    import lombok.Data;
    
    import javax.xml.bind.annotation.*;
    import java.util.Date;
    import java.util.Set;
    
    /**
     * @author : harara
     * @version : 2.0
     * @date : 2020/5/21 10:12
     */
    @XmlRootElement
    @Data
    public class Person {
    
    
        private int id;
    
        private String name;
    
        private String gender;
    
        private String addr;
    
        private String area;
    
    }

    TEST:

    @Test
    public void generateXml(){
        Person person  = new Person(1,"harara","女","湖南","china");
        File file = new File("./src/test/file/person.xml");
        JAXBContext jc = null;
        try{
            //根据person类生成上下文对象
            jc = JAXBContext.newInstance(Person.class);
            //从上下文中获取Marshaller对象,用作将bean编组(转化)为xml
            Marshaller marshaller = jc.createMarshaller();
            //以下是为生成xml做的一些配置
            //格式化输出,即按标签自动换行,否则就是一行输出
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true);
            //设置编码(默认编码就是utf-8)
            marshaller.setProperty(Marshaller.JAXB_ENCODING,"utf-8");
            //是否省略xml头信息,默认不省略(false)
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT,false);
            //编组
            marshaller.marshal(person,file);
            System.out.println("对象转换成xml文件成功");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    @Test
    public void generateBean(){
        File file = new File("./src/test/file/person.xml");
        JAXBContext jc = null;
        try{
            jc = JAXBContext.newInstance(Person.class);
            Unmarshaller uma = jc.createUnmarshaller();
            Person person = (Person) uma.unmarshal(file);
            System.out.println(person);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    测试结果

    generateXml():

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <person>
        <addr>湖南</addr>
        <area>china</area>
        <gender></gender>
        <id>1</id>
        <name>harara</name>
    </person>

    xml相当与该xsd文件:

    <xs:element name="person">
        <xs:complexType>
          <xs:sequence>
            <xs:element type="xs:string" name="addr" minOccurs="0"/>
            <xs:element type="xs:string" name="area" minOccurs="0"/>
            <xs:element type="xs:string" name="gender" minOccurs="0"/>
            <xs:element type="xs:int" name="id" minOccurs="0"/>
            <xs:element type="xs:string" name="name" minOccurs="0"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

     

    generateBean()

    输出:

    Person(id=1, name=harara, gender=女, addr=湖南, area=china)

     

    注:从jdk1.7开始,JAXB就对解组和编组的方法进行了更简单的封装,所以实际项目中除非自己要进行个性化设置,否则大可不用自己再创建JAXBContext实例,直接通过JAXB静态调用相应的工具方法就行了,于是上面的测试方法可以写的更简练些:

    @Test
    public void beanToxml(){
        Person person  = new Person(1,"harara","女","湖南","china");
        File file = new File("./src/test/file/person.xml");
        JAXB.marshal(person,file);
        System.out.println("对象转换成xml文件成功");
    }
    
    
    @Test
    public void XmlTobean(){
        File file = new File("./src/test/file/person.xml");
        Person person = JAXB.unmarshal(file,Person.class);
        System.out.println(person);
    }

     

    三、常用注解

    @XmlRootElement

    作用和用法

    类级别的注解,将类映射为xml全局元素,也就是根元素。就像spring配置文件中的beans。上面的例子中我将该注解用在了person类上,生成了<person>根元素。常与@XmlType@XmlAccessorType@XmlAccessorOrder连用

    属性

     该注解含有namenamespace两个属性,namespace属性用于指定生成的元素所属的命名空间。name属性用于指定生成元素的名字,若不指定则默认使用类名作为元素名。修改上面的例子,在该注解上使用name属性

     生成的xml文件

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human >
          <addr>湖南</addr>
          <area>china</area>
          <gender></gender>
    <id>1</id>
          <name>harara</name>
    </human>

     

    @XmlElement

    作用和用法

    字段,方法,参数级别的注解。该注解可以将被注解的字段(非静态),或者被注解的get/set方法对应的字段映射为本地元素,也就是子元素。默认使用字段名或get/set方法去掉前缀剩下部分小写作为元素名(在字段名和get/set方法符合命名规范的情况下)。上面例子中,idaddrnamegenderarea都被映射成了<person>元素的子元素。下文会配合@XmlAccessorType注解详细讲解该注解的用法。常熟@XmlValue@XmlJavaTypeAdapter,@XmlElementWrapper连用

    属性

    该注解的属性常用的属性有:nameniliablerequirednamespacedefaultValue

    name属性可以指定生成元素的名字,同@XmlRootElement注解的name属性一样,不再举例。

    nillable属性可以指定元素的文本值是否可以为空,默认为false。修改上面例子:

     则生成的xsd(为了节省篇幅,只截取必要的片段)

    <xs:element name="name" type="xs:string" nillable="true" minOccurs="0"/>

     requred属性可以指定元素是否必须出现,默认为false,所以在xsd中会有对应属性minOccurs=”0”。

    <xs:element name="name" type="xs:string" nillable="true" minOccurs="1"/>

    namespace属性可以指定该元素所属的命名空间

    defaultValue属性可以指定该元素默认的文本值

    @XmlAttribute

    作用和用法

    字段和方法级别的注解。该注解会将字段或get/set方法对应字段映射成本类对应元素的属性,属性名默认使用字段名或get/set方法去掉前缀剩下部分首字母小写(在字段名和get/set方法符合命名规范的情况下)

     生成的xml

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human gender="女">
        <id>1</id>
        <name>harara</name>
        <addr>湖南</addr>
        <area>china</area>
    </human>

    对应的xsd

    <xs:element name="human">
        <xs:complexType>
          <xs:sequence>
            <xs:element type="xs:string" name="addr"/>
            <xs:element type="xs:string" name="area"/>
            <xs:element type="xs:byte" name="id"/>
            <xs:element type="xs:string" name="name"/>
          </xs:sequence>
          <xs:attribute type="xs:string" name="gender"/>
        </xs:complexType>
      </xs:element>

    属性

    该注解有namerequirednamespace三个属性。用法和@XmlElement注解相同。

     

    @XmlTransient

    作用和用法

    类,字段,方法级别的注解。可使JAXB在映射xml元素时忽略被注解的类,字段,get/set对应字段。

    需要注意的是该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错

     

     生成的xml

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human>
        <name>harara</name>
        <gender></gender>
        <addr>湖南</addr>
        <area>china</area>
    </human>

    属性

    该注解没有属性

     

    @XmlAccessorType

    包和类级别的注解javaEEAPI对该注解的解释是:控制字段是否被默认序列化。通俗来讲,就是决定哪些字段或哪些get/set方法对应的字段会被映射为xml元素,需要注意的是字段或get/set方法的访问权限(public/private)会影响字段是否被映射为xml元素,下面会详细讲解

    属性

    该注解只有一个value属性,可取的值是一个名为XmlAccessType的枚举类型的值,下面详细看一下这几个值分别有什么用:

    XmlAccessType.PROPERTY

    官方解释

    Every getter/setter pair in a JAXB-bound class will be automatically bound to XML, unless annotated by {@link XmlTransient}.
    jaxb绑定类中的每个getter/setter对都将自动绑定到XML,除非用@XmlTransient注解。
    Fields are bound to XML only when they are explicitly annotated by some of the JAXB annotations.
    只有在某些JAXB注释显式地注解字段时,字段才被绑定到XML。

    补充

    1、当使用了该值,只要字段有对应的get/set方法对(注意是成对出现,只有其中一个不会发生映射),不需要使用@XmlElement注解,不论该方法的访问权限是什么(即使是private)jaxb就会将该字段映射成xml元素。不过最好加上@XmlElement注解,get/set方法任选一个即可,都加上会报错。

    2、若一个字段有set/get方法对但又在字段上添加@XmlElement注解会报属性重复的错误

    3、若没有get/set方法对,则需要在字段上使用@XmlElement注解才可以映射成xml元素,否则不会发生映射。

    4、get/set方法上使用了@XmlTransient注解,但想要对应字段发生映射,需要在对应字段上添加@XmlElement注解,此时不会报错,并将该字段映射为xml元素

     

    XmlAccessType.FIELD

    官方解释

    Every non static, non transient field in a JAXB-bound class will be automatically bound to XML, unless annotated by {@link XmlTransient}.
    jaxb绑定类中的每个非静态、非瞬态字段都将自动绑定到XML,除非使用@XmlTransient进行注释。
    Getter/setter pairs are bound to XML only when they are explicitly annotated by some of the JAXB annotations.
    只有当某些JAXB注释显式地对getter/setter对进行注释时,它们才会绑定到XML。

    补充

    1、每个非静态的字段(无论访问权限如何)都会被jaxb映射为xml元素,即使没有get/set方法对,即使没有使用@XmlElement元素,但最好加上该注解以表明该字段要被映射为xml元素。

    2、虽然没有get/set方法对,也会发生映射,但加上get/set方法对也不会报错,为我们经常会使用这两个方法。但注意,不能在这两个方法上使用@XmlElement方法,否则会报属性重复的错误。

    3、若在字段上使用了@XmlTransient注解,但还想让该字段发生映射,需要在该字段对应的get/set方法上添加@XmlElement

     

    XmlAccessType.PUBLIC_MEMBER(该值为默认值)

    Every public getter/setter pair and every public field will be automatically bound to XML, unless annotated by {@link XmlTransient}.
    每个公共getter/setter对和每个公共字段都将自动绑定到XML,除非使用@XmlTransient注释。
    Fields or getter/setter pairs that are private, protected, or defaulted to package-only access are bound to XML only when they areexplicitly annotated by the appropriate JAXB annotations.
    只有在适当的JAXB注释显式地注释了private,protected,defaulted字段或getter/setter对之后,才会将它们绑定到XML。

    补充

    1、每个访问权限为public的字段,或者每个访问权限为publicget/set方法对,都会将字段映射为xml元素,即使不使用@XmlElement,但最好加上。不可同时存在public字段和对应的get/set方法对,不然会报属性重复的错误

    2、若使用@XmlElement注解,需要注意只能在字段或get/set方法添加,两者任选其一,否则会报属性重复的错误

    3、get/set方法为public并使用了@XmlTransient,字段不为public,需要在字段上添加@XmlElement才会发生映射。

    4、若字段为public并使用了@XmlTransientget/set方法不为public,需要在get/set方法上使用@XmlElement才会映射

     

    XmlAccessType.NONE

     官方解释

    None of the fields or properties is bound to XML unless they are specifically  annotated with some of the JAXB annotations.
    任何字段或属性都不会绑定到XML,除非使用某些JAXB注释对它们进行特别注释。

     补充

    任何字段,get/set方法对都不会发生映射,除非使用某些注解,如@XmlElement,@XmlElementWrapper等。

     

    @XmlAccessorOrder

     作用和用法

     包和类级别的注解控制生成元素的顺序

     属性

    只有一个value属性,可取的值是一个名为XmlAccessOrder的枚举类型的值

    XmlAcessOrder.UNDEFINED(默认) 代表按照类中字段的顺序生成元素的顺序

    XmlAccessOrder.ALPHABETICAL 代表按照字母表的顺序生成元素排序。但奇怪的是,只有jaxb按照XmlAccessType.FIELD生成元素时,默认值才会生效,否则总是按照字母表的顺序排序。

    @XmlElementWrapper

    作用和用法

     字段和方法级别的注解。围绕被映射的xml元素生成包装元素。主要用在集合对象映射后生产包装映射结果的xml元素。

     属性

     该注解有name,nilable,namespace,required四个属性,用法同上,不再赘述。

     修改上面的例子,添加一个Hobby类,在Person类中添加一个Hobby类的Set集合,修改如下

     Hobby类:

    @XmlRootElement
    @Data
    public class Hobby {
    
        private String eat;
    
        private String drink;
        
    }

     Person 

    @XmlRootElement(name = "human")
    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public class Person {
    
        @XmlTransient
        private int id;
    
        private String name;
    
        private String gender;
    
        private String addr;
    
        private String area;
        
        private Set<Hobby> hobby;
    }

     生成的xml

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human>
        <name>harara</name>
        <gender></gender>
        <addr>湖南</addr>
        <area>china</area>
        <hobby>
            <drink>茶颜悦色</drink>
            <eat>大白菜</eat>
        </hobby>
        <hobby>
            <drink>烧仙草</drink>
            <eat>小白菜</eat>
        </hobby>
    </human>

    但同一元素应该被”包装”一下才显得有层次感,所以可以使用@XmlElementWrapper来实现:

     生成的xml

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human>
        <name>harara</name>
        <gender></gender>
        <addr>湖南</addr>
        <area>china</area>
        <hobbies>
            <hobby>
                <drink>茶颜悦色</drink>
                <eat>大白菜</eat>
            </hobby>
            <hobby>
                <drink>烧仙草</drink>
                <eat>小白菜</eat>
            </hobby>
        </hobbies>
    </human>

    @XmlJavaTypeAdapter

    作用和用法

    包、类、字段、方法、参数级别的注解。解决java日期(Date),数字(Number)格式化问题。直接看例子,修改Person类,添加一个Date类型字段:

    Person

     生成的xml

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human>
        <birthday>2020-05-21T18:26:24.995+08:00</birthday>
        <id>1</id>
        <name>harara</name>
        <gender></gender>
        <addr>湖南</addr>
        <area>china</area>
        <hobbies>
            <hobby>
                <drink>茶颜悦色</drink>
                <eat>大白菜</eat>
            </hobby>
            <hobby>
                <drink>烧仙草</drink>
                <eat>小白菜</eat>
            </hobby>
        </hobbies>
    </human>

    这样的date格式显然令人不满意,我们需要例如“2018/05/20 18:26:24”这样的格式。这就需要@XmlJavaTypeAdapter注解,自定义一个适配器来解决这个问题。该注解的用法就是自定义适配器并继承XmlAdapter类,实现里面的marshalunmarshal方法,并在该注解上引用。修改例子

     自定义的DateAdapter:

    public class DateAdapter extends XmlAdapter<String,Date> {
    
    
        @Override
        public Date unmarshal(String v) {
            try {
                Date date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(v);
                return date;
            } catch (ParseException e) {
                e.printStackTrace();
                return null;
            }
    
        }
    
        @Override
        public String marshal(Date v) {
            String dateStr = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(v);
            return dateStr;
        }
    
    }

    Person

     生成的xml

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <human>
        <birthday>2020/05/21 18:30:43</birthday>
        <id>1</id>
        <name>harara</name>
        <gender></gender>
        <addr>湖南</addr>
        <area>china</area>
        <hobbies>
            <hobby>
                <drink>茶颜悦色</drink>
                <eat>大白菜</eat>
            </hobby>
            <hobby>
                <drink>烧仙草</drink>
                <eat>小白菜</eat>
            </hobby>
        </hobbies>
    </human>

    属性

    常用的就是value属性,其他属性请自行研究

    @XmlValue

     作用和用法

     字段和方法级别的注解,该注解的作用,简单理解就是定义xml元素文本值的类型,例如在一个类的String类型字段上使用该注解,则生成的元素文本值类型就是xs:string,也就是定义一个xsd中的complexType

     属性

     无

    @XmlType

     作用和用法

     类级别的注解。该注解有些复杂,主要使用的是它的propOrder属性,简单来说是用来定义xsd中的simpleTypecomplexType,从生成的xml来看,它的作用就是指定生成元素的顺序,具体看下图

     简单解释下每行什么意思

    1、若指定该注解的propOrder{},会生成ComplexType并且使用xs:all指示器,表示所有被映射的元素都必须出现在xml

    2、propOrder的值为{“name”,”addr”,”area”}(大括号中都是Person类的字段名称),会生成ComplexType并使用xs:sequence指示器,表示生成的xml元素必须按照propOrder指定的顺序出现,也就间接实现了排序

    3、若不指定propOrder属性(这与指定propOrder但值为{}不同),没有字段,会生成ComplexType并包含一个空的xs:sequence指示器

    4、若不指定propOrder属性,但含有@XmlValue注解的字段和被@XmlAttribute注解的字段,会生成一个含有simpleContentComplexType

    5、若不指定propOrder属性,但含有被@XmlValue注解的字段而没有被@XmlAttribute注解的字段,会生成一个含有simpleTypeComplexType

    参考地址:https://blog.csdn.net/wn084/article/details/80853587

     

     

     

     

     

  • 相关阅读:
    wu
    Win10编译cuda版OpenCV
    Windows编译OpenCV可能下载失败的文件
    20220419Servlet和HTTP请求协议
    20220418Tomcat
    比 Navicat 还要好用、功能更强大的工具!
    Java 8的18个常用日期处理
    Oracle 执行存储过程五种方法(带参数& 不带参数)
    帆软设置浏览内容宽度为屏幕宽度
    帆软参数为空查询全部
  • 原文地址:https://www.cnblogs.com/kiko2014551511/p/12963453.html
Copyright © 2020-2023  润新知