Jaxb使用

一、概述 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 中会表现为:



      
      
      


  1. @XmlTransient   用于标识在由java对象映射xml时,忽略此属性。即,在生成的xml文件中不出现此元素。
  2. @XmlJavaTypeAdapter   常用在转换比较复杂的对象时,如map类型或者格式化日期等。使用此注解时,需要自己写一个adapter类继承XmlAdapter抽象类,并实现里面的方法。
    @XmlJavaTypeAdapter(value=xxx.class),value为自己定义的adapter类 XmlAdapter定义如下:
public abstract class XmlAdapter {  
   // 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 animals = Arrays.asList(new Dog(), new Cat(), new Pig());
}

结果是:



    
        big
    
    
        red
    
    
        200kg
    

优化处理,使用@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 animals = Arrays.asList(new Dog(), new Cat(), new Pig());
}

结果是:



    
        
            big
        
        
            red
        
        
            200kg
        
    

其他类定义如下:

//这里不能使用接口, 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 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);
    }

结果是:




    zhangsan





    big
    
        zhangsan
    

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

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

结果:



    big
    
        zhangsan
    
    11

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

你可能感兴趣的:(Jaxb使用)