欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Jaxb使用

程序员文章站 2022-03-20 17:57:40
...

一、概述 JAXB(Java Architecturefor XML Binding)是一个业界的标准,它是一个处理XML文档的易用框架,即可以根据XML Schema产生Java类的技术。与之前的处理方式(比如DOM解析)相比,它的优势在于能够将XML文档直接与java对象绑定,包括序列化(java ->xml)和反序列化(xml -> java),而DOM解析仅仅能够得到一个string类型的节点树,我们可以把jaxb理解为能够对象化处理XML的工具。 就像ORM能够将数据库记录映射为JAVA对象一样,JAXB将XML元素映射为JAVA对象。

二、常用注解

  1. @XmlRootElement   类级别注解,顶层元素,对应xml文件中的根节点。例如:
@XmlRootElement //默认转化根节点名称是person,可以通过name属性修改根节点名称
public class Person{
       ..
}
  1. @XmlAccessorType   用于指定由java对象生成xml文件时对java对象属性的访问方式;作用于包或者顶层元素上,有四个枚举值:
    a、XmlAccessType.FELD:java对象中的所有非static 非 transient 的成员变量;
    b、XmlAccessType.PROPERTY:java对象中所有通过getter/setter对方式访问的成员变量;
    c、XmlAccessType.NONE:java对象的所有属性都不映射为xml的元素,除非明确的使用@XmlElement或@XmlAttribute修饰;
    d、XmlAccessType.PUBLIC_MEMBER:java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量,默认方式。
  2. @XmlElement   用在java类的属性上,用于将属性映射为xml的子节点,注意:默认情况下,私有属性是不会被映射的,但可以通过该注解映射私有成员变量,例如:
@XmlElement //默认元素节点名称是age,可以通过name属性修改xml节点名称
private String age; 
  1. @XmlAttribute   用于把java对象的属性映射为xml的属性;例如:
@XmlAttribute //默认属性名称是id,可以通过name属性修改xml属性名称
private String id;
  1. @XmlAccessorOrder   用于对java对象生成的xml元素进行排序。作用于*元素上,它有两个属性值:
    a、AccessorOrder.ALPHABETICAL:对生成的xml元素按字母顺序排序;
    b、XmlAccessOrder.UNDEFINED:不排序。

  2. @XmlType   作用于顶层元素或枚举类上,用它标注的类在映射后的 schema 中中会以一个 XML 复杂数据类型的形式出现。我们可以通过 @XmlType 注解的 name 属性来定制映射的 XML 数据类型的名称,用 propOrder 属性来定制映射后的复杂数据类型的内容顺序等。例如:

@XmlType(name = "SubPerson", propOrder = { "name", "id", "age"})
public class Person{
    private int id;
    private String name;
    private int age;
    ..
}

这个 Java 类在映射后的 Web 服务 schema 中会表现为:

<xs:complexType name="SubPerson">
<xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="id" type="xs:int"/>
      <xs:element name="age" type="xs:int"/>
</xs:sequence>
</xs:complexType>
  1. @XmlTransient   用于标识在由java对象映射xml时,忽略此属性。即,在生成的xml文件中不出现此元素。
  2. @XmlJavaTypeAdapter   常用在转换比较复杂的对象时,如map类型或者格式化日期等。使用此注解时,需要自己写一个adapter类继承XmlAdapter抽象类,并实现里面的方法。
    @XmlJavaTypeAdapter(value=xxx.class),value为自己定义的adapter类 XmlAdapter定义如下:
public abstract class XmlAdapter<ValueType,BoundType> {  
   // Do-nothing constructor for the derived classes.  
   protected XmlAdapter() {}  
   // Convert a value type to a bound type.  
   public abstract BoundType unmarshal(ValueType v);  
   // Convert a bound type to a value type.  
   public abstract ValueType marshal(BoundType v);  
}  
  1. @XmlAnyAttribute和@XmlAnyElement    任意随机的attribute和element。
  2. @XmlElementWrapper   生成一个包装 XML表示形式的包装器元素。 此元素主要用于生成一个包装集合的包装器 XML元素。
  3. @XmlElements   作为一个容器,是一个collection集合,可以包含不同类型,也可以用继承中的子类,详解如下:
@XmlRootElement
public class Person {
    @XmlElements({
        @XmlElement(name="dog", type=Dog.class),
        @XmlElement(name="cat", type=Cat.class),
        @XmlElement(name="pig", type=Pig.class)
    })
    public List<Animal> animals = Arrays.asList(new Dog(), new Cat(), new Pig());
}

结果是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
    <dog>
        <size>big</size>
    </dog>
    <cat>
        <color>red</color>
    </cat>
    <pig>
        <weight>200kg</weight>
    </pig>
</person>

优化处理,使用@XmlElementWrapper来给集合属性增加一个wrapper:

@XmlRootElement
public class Person {
    @XmlElementWrapper(name="animals")
    @XmlElements({
        @XmlElement(name="dog", type=Dog.class),
        @XmlElement(name="cat", type=Cat.class),
        @XmlElement(name="pig", type=Pig.class)
    })
    public List<Animal> animals = Arrays.asList(new Dog(), new Cat(), new Pig());
}

结果是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
    <animals>
        <dog>
            <size>big</size>
        </dog>
        <cat>
            <color>red</color>
        </cat>
        <pig>
            <weight>200kg</weight>
        </pig>
    </animals>
</person>

其他类定义如下:

//这里不能使用接口, JAXB 无法处理接口
public abstract class Animal {} 
public class Cat extends Animal{
    public String color = "red";
}
public class Dog extends Animal{
    public String size = "big";
}
public class Pig extends Animal{
    public String weight = "200kg";
}
//Person类是JAXB根元素,包含一个Animal的集合
@XmlRootElement
public class Person {
    public List<Animal> animals = Arrays.asList(new Dog(), new Cat(), new Pig());
}

三、序列化和反序列化
    不管是序列化还是反序列化,都需要获得的就是JAXBContext对象,它提供了JAXB API 的入口,我们使用JAXBContext.newInstance静态方法来获得它,问题在于需要传入的参数。有两种方法:

  1. 编写XML Schema,然后使用xjc实用工具编译;
  2. 手动编写pojo,使用特定注解修饰。

通过编写Java代码实现如下(通常情况下,顶层元素就足够了,因为JAXB将会从顶层元素开始递归引用到 顶层元素涉及到的类型(比如实例变量的类型),但是顶层元素的子类是不会被JAXB处理到的):

@XmlRootElement
public class Person {
    public String name = "zhangsan";
}

@XmlRootElement
public class Dog {
    public String size = "big";
    public Person owner = new Person();
}

@XmlRootElement
public class LittleDog extends Dog{
    public int age = 11;
}

我们在创建JAXBContext的时候,如果仅仅传入Dog.class,那么Dog和Person会被JAXB处理,而LittleDog则不会,如果我们使用JAXB处理LittleDog,那么它会被当成Dog来处理。

public static void main(String[] args) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(Dog.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        
        marshaller.marshal(new Person(), System.out);
        marshaller.marshal(new LittleDog(), System.out);
    }

结果是:

<!-- 下面是Person对象的序列化结果,因为Person被Dog引用,所以也被JAXB处理了 -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
    <name>zhangsan</name>
</person>

<!-- 注意下面是LittleDog的序列化结果,很显然它仅仅被当做一个Dog对象处理了-->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<dog>
    <size>big</size>
    <owner>
        <name>zhangsan</name>
    </owner>
</dog>

我们除了明确的把LittleDog.class也传入到JAXBContext.newInstance方法中去外,还可以使用@XmlSeeAlso,如下:

@XmlRootElement
//XmlSeeAlso的含义就是说当JAXB处理Dog的时候也处理哪些类型(先显示父类然后是子类)
@XmlSeeAlso({LittleDog.class})
public class Dog {
    public String size = "big";
    public Person owner = new Person();
}

结果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<littleDog >
    <size>big</size>
    <owner>
        <name>zhangsan</name>
    </owner>
    <age >11</age >
</littleDog >

转载于:https://my.oschina.net/u/2500438/blog/1501606