当前位置:首页 > 技术分析 > 正文内容

「Java 开发工具 · 建议收藏」详细讲解:Xstream 对象转 XML工具

ruisui883个月前 (02-04)技术分析15

一、介绍

XStream 是一个简单的基于 Java 库,Java 对象序列化到 XML,反之亦然 (即:可以轻易的将 Java 对象和 xml 文档相互转换)。

特点

  1. 使用方便 - XStream 的 API 提供了一个高层次外观,以简化常用的用例。
  2. 无需创建映射 - XStream 的 API 提供了默认的映射大部分对象序列化。
  3. 性能 - XStream 快速和低内存占用,适合于大对象图或系统。
  4. 干净的 XML - XStream 创建一个干净和紧凑 XML 结果,这很容易阅读。
  5. 不需要修改对象 - XStream 可序列化的内部字段,如私有和最终字段,支持非公有制和内部类。默认构造函数不是强制性的要求。
  6. 完整对象图支持 - XStream 允许保持在对象模型中遇到的重复引用,并支持循环引用。
  7. 可自定义的转换策略 - 定制策略可以允许特定类型的定制被表示为 XML 的注册。
  8. 安全框架 - XStream 提供了一个公平控制有关解组的类型,以防止操纵输入安全问题。
  9. 错误消息 - 出现异常是由于格式不正确的 XML 时,XStream 抛出一个统一的例外,提供了详细的诊断,以解决这个问题。
  10. 另一种输出格式 - XStream 支持其它的输出格式,如 JSON

二、使用案例

  1. JDK 环境:JDK8,其他版本的JDK6+
  2. maven:3.8.6
  3. Xstream:1.4.20
  4. maven 版本快速查找网站:Maven搜索-最快捷的Maven搜索-由源码阅读网提供技术服务

(1)引入 maven 依赖

提醒:本篇文章使用到的依赖,请确保依赖存在再进行亲自体验测试;


    org.projectlombok
    lombok
    true




    com.thoughtworks.xstream
    xstream
    1.4.20



    org.codehaus.jettison
    jettison
    1.5.4


  
  
    com.fasterxml.jackson.core  
    jackson-databind  
    2.13.0  

(2)对象转 XML:基础简单使用

① 控制层直接输出 XML 格式数据

@RestController
@RequestMapping("/demo")
public class DemoController {

    @RequestMapping(value = "/hello" ,produces = {"application/xml;"})
    public String showHelloWorld(){
        Employee e1 = Employee.builder().firstName("张").lastName("三").age(18).salary(10000).gender("Male").build();
        // Serializing a Java object into XML
        XStream xStream = new XStream(new DomDriver());
        String xml = xStream.toXML(e1); // Converting it to XML
        return xml;
    }
}

演示结果:

(3)对象转 XML:三种方式

public static void main(String[] args) {
    Employee employee = Employee.builder().firstName("张").lastName("三").age(18).salary(10000).gender("Male").build();

    //XML序列化方式一:需要XPP3库
    XStream xstream_1 = new XStream();
    String xml_1 = xstream_1.toXML(employee);
    System.out.println("xml_1: (需要XPP3库)\n" + xml_1);

    // XML序列化方式二:不需要XPP3库
    XStream xstream_2 = new XStream(new DomDriver());
    String xml_2 = xstream_2.toXML(employee);
    System.out.println("xml_2: (不需要XPP3库)\n" + xml_2);

    // XML序列化方式三:不需要XPP3库开始使用Java6
    XStream xstream_3 = new XStream(new StaxDriver());
    xstream_3.alias("员工",Employee.class);//为类名节点重命名
    String xml_3 = xstream_3.toXML(employee);
    System.out.println("xml_3:(不需要XPP3库开始使用Java6) \n" + xml_3);

}

输出结果:

xml_1: (不需要XPP3库)

  
  
  10000
  18
  Male


xml_2: (需要XPP3库)

  
  
  10000
  18
  Male


xml_3:(不需要XPP3库开始使用Java6) 
<员工>1000018Male

(3)对象转 XML:重命名节点名

官方直达示例教程:XStream - 别名教程 (x-stream.github.io)

  1. 两种方法:
    1. 方法1:① 在对象上添加别名注解;② 使用时开启注解和应用注解;
    2. 方法2:无需再对象上添加对应的类/属性别名注解,直接再使用时 alias() / aliasField() 即可;

【1】对象属性标记注解

@Data
@Builder
@XStreamAlias("员工")
public class Employee {
    @XStreamAlias("名")
    public String firstName;
    @XStreamAlias("姓")
    public String lastName;
    @XStreamAlias("薪资")
    public int salary;
    @XStreamAlias("年龄")
    public int age;
    @XStreamAlias("性别")
    public String gender;
}

【2】开启注解识别

public static void beanToXmlAlias() {
    Employee employee = Employee.builder().firstName("张").lastName("三").age(18).salary(10000).gender("Male").build();

    //XML序列化方式:需要XPP3库
    XStream xstream_1 = new XStream();
    xstream_1.processAnnotations(Employee.class);// 应用Employee类的注解
    xstream_1.autodetectAnnotations(true);// 自动检测注解
    String xml_1 = xstream_1.toXML(employee);
    System.out.println("xml_1: (需要XPP3库)\n" + xml_1);
}

【3】结果展示

【4】扩展:另一种设置别名的方式

public static void beanToXmlAlias2() {
    Person person = Person.builder().id(1).name("King").build();
    XStream xstream_1 = new XStream();

    // 1.设置类别名
    xstream_1.alias("person", Person.class);
    // 2.设置属性别名
    xstream_1.aliasField("personId", Person.class, "id");// 将属性id设置别名为 personId
    xstream_1.aliasField("personName", Person.class, "name");// 将属性name设置别名为 personName
    // 3.其他 还可以设置包别名等

    String xml_1 = xstream_1.toXML(person);
    System.out.println("xml_1: (需要XPP3库)\n" + xml_1);
}

结果展示:


(4)XML格式转对象:基础使用

【1】定义反序列化对象

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Person {
    private Integer id;
    private String name;
}

【2】简单使用示例

public static void xmlToBean() {
    Person bean = Person.builder().id(1).name("Drew").build();
    XStream xstream = new XStream(new DomDriver());//设置Json解析器
    //Json序列化
    String xml = xstream.toXML(bean);
    System.out.println(xml);

    //【重点】Json反序列化(注意:需要设置可访问的类对象机制)
    xstream.allowTypes(new Class[]{Person.class});
    bean = (Person) xstream.fromXML(xml);
    System.out.println(bean);
}

【3】结果展示


【踩坑记录】反序列化的时候出现Exception in thread "main" com.thoughtworks.xstream.security.ForbiddenClassException

解决方案:

XStream xstream = new XStream();  
// 允许反序列化对应的类, 如果Person属性是一个类对象,也需要在这里面包含,否则依旧会出现此问题!
xstream.allowTypes(new Class[]{Person.class});

请注意,在使用 XStream 时,特别是当处理来自不受信任的源的数据时,要格外小心,以确保你的应用不会被恶意输入所利用。

*(5)XML 转 对象:增加别名使用示例

【1】对象属性标记注解

对反序列化的对象的属性进行标记别名,使用注解 @XStreamAlias 即可。

import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
@XStreamAlias("人")
public class Person {
    @XStreamAlias("编号")
    private Integer id;
    @XStreamAlias("名称")
    private String name;
}

【2】使用示例

别名替换了节点,不会被反序列化的时候识别的,请在传入的 XML文件中使用对应接受的DTO属性名保持一致。

【3】结果展示

无法识别,不展示!

(6)xstream框架将 对象转JSON :简单使用示例

【1】定义对象

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Person {
    private Integer id;
    private String name;
}

【2】简单使用

public static void xmlToJson() {
    Person person = new Person(1, "Banana");
    XStream xstream = new XStream(new JettisonMappedXmlDriver());
    xstream.setMode(XStream.NO_REFERENCES);
    xstream.alias("person", Person.class);
	// 输出: object → json : {"person":{"id":1,"name":"Banana"}}
    System.out.println(" object → json : " + xstream.toXML(person));

    xstream.aliasField("personId", Person.class, "id");
    xstream.aliasField("personName", Person.class, "name");
    // 输出: object → json alias : {"person":{"personId":1,"personName":"Banana"}}
    System.out.println(" object → json alias : " + xstream.toXML(person));
}

【踩坑记录】出现异常 Exception in thread "main" java.lang.NoClassDefFoundError: org/codehaus/jettison/mapped/Configuration

解决方案:引入 maven 依赖:即可。


    org.codehaus.jettison
    jettison
    1.5.4

(7)xstream 的 XML 转 JSON

将 xml 转成JSON 则需要 xstream 框架兼容其他的JSON工具依赖,使用第三方的转换驱动进行替换。

【1】引入maven依赖:jackson

注意:如果是 Spring Boot 框架则无需引入 Jackson 框架(Spring Boot 内置了 Jackson 依赖)

  
      
      
        com.thoughtworks.xstream  
        xstream  
        1.4.18  
      

      
      
        com.fasterxml.jackson.core  
        jackson-databind  
        2.13.0  
      

【2】使用演示

public static void xmlToJson() throws JsonProcessingException {
    // XML 字符串
    String xml = "John Doe30";

    // 1.使用 XStream 将 XML 反序列化为 Java 对象
    XStream xstream = new XStream();
    xstream.allowTypes(new Class[]{Person.class});// 注意1
    xstream.alias("person", Person.class); // 注意2:需要和XML文件的根节点一致
    Person person = (Person) xstream.fromXML(xml);

    // 2.使用 Jackson 将 Java 对象转换为 JSON 字符串
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(person);

    // 3.输出 JSON 字符串
    System.out.println(json);
}

测试结果:

扩展:更复杂的对象(map/list/嵌套属性的对象)转换请看友情链接:xStream转换XML、JSON - nevergiveupzeng - 博客园 (cnblogs.com)

(8)XStream 自定义转换器

官方直达示例教程地址:XStream - Converter Tutorial (x-stream.github.io)

【1】定义示例对象

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Person {
    private Integer id;
    private String name;
}

【2】定义自定义转换器

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class PersonConverter implements Converter {
    //定义转换器能转换的JavaBean类型
    @Override
    public boolean canConvert(Class type) {
        return type.equals(Person.class);
    }

    //把对象序列化成XML或Json
    @Override
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
        Person person = (Person) value;
        writer.startNode("编号");
        writer.setValue(person.getId() + "");
        writer.endNode();
        writer.startNode("姓名");
        writer.setValue(person.getName());
        writer.endNode();
        writer.startNode("转换器");
        writer.setValue("自定义的转换器");
        writer.endNode();
    }

    //把XML或Json反序列化成对象
    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        Person person = new Person(1, "Bob");
        // 第一个属性
        reader.moveDown();
        person.setId(Integer.parseInt(reader.getValue()));
        reader.moveUp();
        // 第二个属性
        reader.moveDown();
        person.setName(reader.getValue());
        reader.moveUp();

        return person;
    }
}

【3】测试演示

public static void xmlConvertor() {
    Person bean = new Person(19, "张三");
    XStream xstream = new XStream();
    xstream.registerConverter(new PersonConverter());//注册转换器
    //序列化
    String xml = xstream.toXML(bean);
    System.out.println(xml);
    //反序列化
    xstream.allowTypes(new Class[]{Person.class});
    bean = (Person)xstream.fromXML(xml);
    System.out.println(bean);
}

结果展示:

(9)Xstream 对象流使用方法

使用实例:这里重点展示 输出流的用法。

官方直达示例教程:XStream - Object Streams Tutorial

public static void xstreamStream() throws IOException {
    XStream xstream = new XStream();
    ObjectOutputStream out = xstream.createObjectOutputStream(System.out);
    out.writeObject(new Person(1, "张三"));
    out.writeObject(new Person(2, "李四"));
    out.writeObject("Hello");
    out.writeInt(12345);
    out.close();
}

结果输出:


  
    1
    张三
  
  
    2
    李四
  
  Hello
  12345

(10)Xstream 数据持久化

使用实例如下:① 创建一个 XStream 对象,设置允许访问转化的对象;② 添加对应的XML文件的数据;

官方直达教程示例:XStream - Persistence API Tutorial

public static void xstreamStrategy() {
    XStream xstream = new XStream();
    // 注意:xstream 1.4.20 需要手动允许转换的类型,否则禁止访问Person对象属性
    xstream.allowTypes(new Class[]{Person.class});
    PersistenceStrategy strategy = new FilePersistenceStrategy(new File("./target"), xstream);
    XmlArrayList xmlArrayList = new XmlArrayList(strategy);
    xmlArrayList.add(0, new Person(1, "Bob"));
    xmlArrayList.add(1, new Person(2, "King"));
    xmlArrayList.add(2, new Person(3, "Baby"));
    System.out.println(xmlArrayList);// 此行可以省略(如果无需输出显示)
}

结果展示:

【重要提醒】漏洞修复

xstream 版本在 1.4.11 和 1.4.16 版本的漏洞,任意删除一个文件,请尽快升级到 Xstream 的最新版本(目前版本为 1.4.20)即可。漏洞复现和研究参考地址:xstream 反序列化漏洞研究与修复_xstream不安全的序列号-CSDN博客


附录

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1656.html

标签: objectmapper
分享给朋友:

“「Java 开发工具 · 建议收藏」详细讲解:Xstream 对象转 XML工具” 的相关文章

费用报销管控紧抓三个要点,网上报销系统助力企业做好报销管理

财务人员在进行费用报销管控时,多多少少会遇到一些棘手的情况。费用报销管控的要点是什么?这是很对财务朋友非常关心的一个问题,今天就给大家讲解一下费用报销管控的3个要点!关键点一:要求员工把报销单上面的关键信息填写完整那么报销单上的关键信息有哪些呢?不同的费用类型,关键信息不一样,比如交通费发票,火车票...

Vue.js 组件通信的 3 大妙招

在 Vue.js 中,组件化是其核心概念之一,允许你将复杂的界面拆分成多个独立的、可复用的组件。在构建大型应用时,如何高效地在组件之间传递数据和触发事件是非常重要的。Vue.js 提供了多种方式来处理组件间的通信,下面是最常用的 3 种方式:1.父子组件通信:通过 Props 和 Events在 V...

Gemini应用在Android上广泛推出2.0闪电模式切换器

#头条精品计划# 快速导读谷歌(搜索)应用的测试频道在安卓设备的双子应用中推出了2.0闪电实验功能,现已向稳定用户开放。双子应用通过谷歌应用运行,目前推出的15.50版本中,用户可通过模型选择器体验不同选项,包括1.5专业版、1.5闪电版和2.0闪电实验版。2.0闪电实验模型提供了更快的响应速度和优...

USB电池充电基础:应急指南

USB为便携设备供电与其串行通信功能一样,已经成为一种标准应用。如今,USB 供电已经扩展到电池充电、交流适配器及其它供电形式的应用。应用的普及带来的一个显著效果是便携设备的充电和供电可以互换插头和适配器。因此,相对于过去每种装置都采用专用适配器的架构相比,目前的解决方案允许采用多种电源进行充电。毋...

最快清除数组空值?分享 1 段优质 JS 代码片段!

本内容首发于工粽号:程序员大澈,每日分享一段优质代码片段,欢迎关注和投稿!大家好,我是大澈!本文约 600+ 字,整篇阅读约需 1 分钟。今天分享一段优质 JS 代码片段,用最简洁的代码清除了数组中的空值。老规矩,先阅读代码片段并思考,再看代码解析再思考,最后评论区留下你的见解!const arr...

12种JavaScript中最常用的数组操作整理汇总

数组是最常见的数据结构之一,我们需要绝对自信地使用它。在这里,我将列出 JavaScript 中最重要的几个数组常用操作片段,包括数组长度、替换元素、去重以及许多其他内容。1、数组长度大多数人都知道可以像这样得到数组的长度:const arr = [1, 2, 3]; console.log(a...