JAXB解析xml转换成类的实现方式

 更新时间:2025年11月19日 08:55:37   作者:码上走人  
本文主要介绍了如何使用JAXB将XML配置项转换为Java类,JAXB提供了多种注解,如@XmlRootElement、@XmlElement、@XmlElementWrapper、@XmlAttribute等,可以方便地将XML元素映射为Java对象,并且可以控制生成的XML结构,同时,文章也提到了一些需要注意的问题

项目需要将一些公共配置项写成xml文件,启动时转化成对应的类。

查找了一些资料,发现JAXB完全可以满足自己的功能需求。

pom依赖

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.1</version>
</dependency>

主要注解

@XmlRootElement

@XmlRootElement定义xml根节点的信息。主要功能如下:

1. 将元素与XML模式类型相关联

@XmlRootElement
      class Point {
         int x;
         int y;
         Point(int _x,int _y) {x=_x;y=_y;}
      }
  
//Example: Code fragment corresponding to XML output
marshal( new Point(3,5), System.out);
 <!-- Example: XML output -->  
 <point>    
    <x> 3 </x>
    <y> 5 </y>
</point>


//注释在模式中生成全局元素声明。全局元素声明与类映射到的XML模式类型相关联。

<!-- Example: XML schema definition -->
<xs:element name="point" type="point"/>
<xs:complexType name="point">
       <xs:sequence>
                        <xs:element name="x" type="xs:int"/>
                        <xs:element name="y" type="xs:int"/>
       </xs:sequence>
</xs:complexType>

2. 将全局元素与类所属的XML模式类型相关联

@XmlRootElement(name="PriceElement")
public class USPrice {
    @XmlElement
    public java.math.BigDecimal price;
}


Example: XML schema definition -->   
 <xs:element name="PriceElement" type="USPrice"/>   
<xs:complexType name="USPrice">     
    <xs:sequence>       
    <xs:element name="price" type="xs:decimal"/>     
    </sequence>
</xs:complexType>

@XmlElement

@XmlElement可以将xml元素转为对应的实体属性值。可转化普通属性、数组、对象

1. 将公共非静态非最终字段映射到本地元素

public class USPrice {
  @XmlElement(name="itemprice")
  public java.math.BigDecimal price;
}

<!-- Example: Local XML Schema element -->   
<xs:complexType name="USPrice"/>     
  <xs:sequence>       
    <xs:element name="itemprice" type="xs:decimal" minOccurs="0"/>     
  </sequence>   
</xs:complexType>

2.  映射到可nullable元素。

public class USPrice {
    @XmlElement(nillable=true)
    public java.math.BigDecimal price;
}

<!-- Example: Local XML Schema element -->   
<xs:complexType name="USPrice">     
    <xs:sequence>       
        <xs:element name="price" type="xs:decimal" nillable="true" minOccurs="0"/>     
    </sequence>   
</xs:complexType>

3. 映射到可nullable元素且必填的元素。 

public class USPrice {
    @XmlElement(nillable=true, required=true)
    public java.math.BigDecimal price;
}

<!-- Example: Local XML Schema element -->   
<xs:complexType name="USPrice">     
    <xs:sequence>       
        <xs:element name="price" type="xs:decimal" nillable="true" minOccurs="1"/>     
    </sequence>   
</xs:complexType>

@XmlElements

@XmlElements可以将不同的xml节点转换为实体数组对象。

public class Foo {
     XmlElements(
         XmlElement(name="A", type=Integer.class),
         XmlElement(name="B", type=Float.class)
      )
      public List items;
 }

// items = [1,2.5]时,得到的xml为
 <A> 1 </A>
 <B> 2.5 </B>
 ...

 <!-- XML Schema fragment -->
 <xs:complexType name="Foo">
   <xs:sequence>
     <xs:choice minOccurs="0" maxOccurs="unbounded">
       <xs:element name="A" type="xs:int"/>
       <xs:element name="B" type="xs:float"/>
     <xs:choice>
   </xs:sequence>
 </xs:complexType>

映射到用另一个元素包裹的元素列表

 // Mapped code fragment
  public class Foo {
      XmlElementWrapper(name="bar")
      XmlElements(
          XmlElement(name="A", type=Integer.class),
          XmlElement(name="B", type=Float.class)
      }
      public List items;
  }
映射结果
  <!-- XML Schema fragment -->
  <xs:complexType name="Foo">
    <xs:sequence>
      <xs:element name="bar">
        <xs:complexType>
          <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="A" type="xs:int"/>
            <xs:element name="B" type="xs:float"/>
          </xs:choice>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

使用适配器根据类型更改元素名称 

class Foo {
   XmlJavaTypeAdapter(QtoPAdapter.class)
   XmlElements({
       XmlElement(name="A",type=PX.class),
       XmlElement(name="B",type=PY.class)
   })
   Q bar;
}

XmlType abstract class P {...}
XmlType(name="PX") class PX extends P {...}
XmlType(name="PY") class PY extends P {...}

<!-- XML Schema fragment -->
<xs:complexType name="Foo">
  <xs:sequence>
    <xs:element name="bar">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="A" type="PX"/>
          <xs:element name="B" type="PY"/>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:sequence>
</xs:complexType>

@XmlElementWrapper

围绕XML表示生成包装器元素。

这主要是为了在集合周围生成一个包装器XML元素。

通过这个 @XmlElementWrapper注解可以减少包装类的创建。

 //Example: code fragment    
 int[] names;    
 
 // XML Serialization Form 1 (Unwrapped collection)  
 <names> ... </names>  
 <names> ... </names>    
 
 // XML Serialization Form 2 ( Wrapped collection )  
 <wrapperElement>     
    <names> value-of-item </names>     
    <names> value-of-item </names>     
    ....  
</wrapperElement>

@XmlElementWrapper 需要配合 @XmlElement 一起使用

@XmlList

@XmlList注释允许在单个元素中将多个值表示为空格分隔的标记

@XmlRootElement
  class Foo {
      @XmlElement
      @XmlList
      List<String> data;
  }
  
the above code will produce XML like this:
 <foo>  

         <data>abc def</data>

 </foo>

@XmlAttribute

@XmlAttribute可以获取到xml节点的属性字段值 

@XmlElementRef

该注解所在属性是某些子类的父类,起到引用的作用。

同时标注得有@XmlElementRef的类属性,其子类上需要使用@XmlRootElement标注,否则转换异常,提示找不到具体的引用实现。

另外,转换时,需要将其子类的class一起传递到JAXBContext上下文中,否则也无法转换。

@XmlTransient

通常与 @XmlElement 须搭配使用的。

@XmlElement用在属性上,用于指定生成xml的节点名,@XmlTransient用在对应的getter方法上,起到关联的作用。

@XmlAccessorOrder

控制JAXB 绑定类中属性和字段的排序。

其他

@XmlValue、@XmlEnum、@XmlEnumValue

实现

定义xml信息

<person>
    <id>111111</id>
    <name>lijie</name>
    <address>
        <province></province>
        <city></city>
        <detail></detail>
    </address>
    <attr property="1231321" />
    <items>
        <item>afgafdafd</item>
        <item>adfadfadfa</item>
    </items>
</person>

定义类

这里通过使用@XmlElementWrapper注解配合可以减少包装类的创建

@XmlRootElement(name = "person")
public class Person{
    
    @XmlElement(name = "id")
    String id;

    @XmlElement(name = "name")
    String name;

    @XmlElement(name = "address")
    Address addrss;

    @XmlElement(name = "attr")
    Attributes attributes;
    
    @XmlElementWrapper(name =  "items")
    @XmlElement(name = "item")
    List<Item> items;
}

public class Address{
    
    @XmlElement(name = "province")
    String province;

    @XmlElement(name = "city")
    String city;
}

public class Item{
    
    @XmlElement(name = "item")
    String des;
}


public class Attributes{
    
    @XmlAttribute(name = "property")
    String des;
}

转换

xml转换为实体类

ClassPathResource resource = new ClassPathResource("xml/SnmpTrapHitRules.xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getStream()));

JAXBContext jaxbContext = JAXBContext.newInstance(SnmpTrapHitRuleDto.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
snmpTrapHitRuleDto = (SnmpTrapHitRuleDto) unmarshaller.unmarshal(reader);

实体类转成xml

 // 创建Person对象
Person person = new Person("张三", 30);

// 创建JAXBContext对象
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);

// 创建Marshaller对象
Marshaller marshaller = jaxbContext.createMarshaller();

// 设置格式化输出
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

// 将Java对象转换为XML字符串
StringWriter stringWriter = new StringWriter();
marshaller.marshal(person, stringWriter);

问题

JAXB要求将注解放到对应的set/get方法上,但是由于我们可能使用的时lombok,没有显示的说明get/set方法,这时候会报错:类的两个属性具有相同名称。

解决办法是在类上加入注解 @XmlAccessorType

  • @XmlAccessorType

类级别的注解。定义这个类中的何种类型需要映射到XML。

解释起来有点拗口,可以通过它的属性值更好理解这个参数的意义。

  • 参数 value

参数 value 可以接受4个指定值,这几个值是枚举类型,方便调用:

  • XmlAccessType.FIELD:映射这个类中的所有字段到XML
  • XmlAccessType.PROPERTY:映射这个类中的属性(get/set方法)到XML
  • XmlAccessType.PUBLIC_MEMBER:将这个类中的所有public的field或property同时映射到XML(默认)
  • XmlAccessType.NONE:不映射

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 浅谈Java8 的foreach跳出循环break/return

    浅谈Java8 的foreach跳出循环break/return

    这篇文章主要介绍了Java8 的foreach跳出循环break/return,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Java 中的 super 关键字用法指南

    Java 中的 super 关键字用法指南

    Java中super关键字用于调用父类构造方法和访问成员,隐式调用无参构造,显式调用有参构造,若父类无无参构造,子类必须显式调用super,以确保正确初始化,本文介绍Java中的super关键字用法指南,感兴趣的朋友一起看看吧
    2025-07-07
  • SpringBoot中@Valid对List校验失效问题的有效解决方法

    SpringBoot中@Valid对List校验失效问题的有效解决方法

    在Spring Boot应用开发中,我们经常需要对传入的请求参数进行校验,以确保数据的合法性和安全性,然而,当我们尝试对列表(List)类型的参数进行校验时,可能会遇到校验失效的问题,本文将详细探讨这一问题的失效原因,并提供有效的解决方法,需要的朋友可以参考下
    2025-07-07
  • java实现多文件上传至本地服务器功能

    java实现多文件上传至本地服务器功能

    这篇文章主要为大家详细介绍了java实现多文件上传至本地服务器功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • idea项目debug模式无法启动的解决

    idea项目debug模式无法启动的解决

    这篇文章主要介绍了idea项目debug模式无法启动的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • SpringBoot如何进行参数校验实例详解

    SpringBoot如何进行参数校验实例详解

    开发过程中,后台的参数校验是必不可少的,下面这篇文章主要给大家介绍了关于SpringBoot如何进行参数校验的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-01-01
  • 解决spring-boot2.0.6中webflux无法获得请求IP的问题

    解决spring-boot2.0.6中webflux无法获得请求IP的问题

    这几天在用 spring-boot 2 的 webflux 重构一个工程,写到了一个需要获得客户端请求 IP 的地方,在写的过程中遇到很多问题,下面小编通过一段代码给大家介绍解决spring-boot2.0.6中webflux无法获得请求IP的问题,感兴趣的朋友跟随小编一起看看吧
    2018-10-10
  • Java 并发编程学习笔记之核心理论基础

    Java 并发编程学习笔记之核心理论基础

    编写优质的并发代码是一件难度极高的事情。Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的,但是当我们对并发编程有了更深刻的认识和更多的实践后,实现并发编程就有了更多的方案和更好的选择。本文是对并发编程的核心理论做了下小结
    2016-05-05
  • springmvc拦截器登录验证示例

    springmvc拦截器登录验证示例

    本篇文章主要介绍了springmvc拦截器登录验证示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • 关于@ApiModel和@ApiModelProperty的使用

    关于@ApiModel和@ApiModelProperty的使用

    这篇文章主要介绍了关于@ApiModel和@ApiModelProperty的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11

最新评论