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

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

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

一、介绍

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工具” 的相关文章

带你五步学会Vue SSR

作者:liuxuan 前端名狮转发链接:https://mp.weixin.qq.com/s/6K6GUHcLwLG4mzfaYtVMBQ前言SSR大家肯定都不陌生,通过服务端渲染,可以优化SEO抓取,提升首页加载速度等,我在学习SSR的时候,看过很多文章,有些对我有很大的启发作用,有些就只是照搬官...

gitlab常用命令大全

GitLab常用命令大全GitLab是一个基于Git的Web平台,它不仅提供代码托管,还集成了持续集成/持续交付(CI/CD)、代码审查、问题追踪等功能。在日常使用GitLab的过程中,我们常常需要使用一系列命令来管理代码仓库、处理分支和标签等。以下是GitLab常用的Git命令大全,并附上详细解释...

继Yuzu后,任天堂要求移除多个Switch模拟器项目

IT之家 7 月 11 日消息,任天堂美国分公司 (Nintendo of America) 已要求移除多个用于模拟 Nintendo Switch 游戏的开源模拟器项目,其中包括 Suyu、Nzu、Uzuy、Torzu、Sudachi 和 Yuzu-vanced 等。这些模拟器均被指控包含绕过任天...

GitLab-合并请求

描述合并请求可用于在您对项目进行的其他人员之间交换代码,并轻松与他们讨论更改。合并请求的步骤步骤1-在创建新的合并请求之前,GitLab中应该有一个创建的分支。您可以参考本章来创建分支-步骤2-登录到您的GitLab帐户,然后转到“ 项目”部分下的项目 -步骤3-单击“ 合并请求”选项卡,然后单击“...

HTML5学习笔记三:HTML5语法规则

1.标签要小写2.属性值可加可不加””或”3.可以省略某些标签 html body head tbody4.可以省略某些结束标签 tr td li例:显示效果:5.单标签不用加结束标签img input6.废除的标签font center big7.新添加的标签将在下一HTML5学习笔记中重点阐述。...

Vue2的16种传参通信方式

前言先直入主题列出有哪些传参方式,下面再通过事例一一讲解。props(父传子)$emit与v-on (子传父)EventBus (兄弟传参).sync与update: (父子双向)v-model (父子双向)ref$children与$parent$attrs与$listeners (爷孙双向)pr...