• 『Java』XStream基础使用与部分源码浅析


    简介

    XStream is a simple library to serialize objects to XML and back again.

    依赖

    XStream使用了XML解析器xpp3_min

            
            <dependency>
                <groupId>com.thoughtworks.xstreamgroupId>
                <artifactId>xstreamartifactId>
                <version>1.4.6version>
            dependency>
            
            
            <dependency>
                <groupId>xpp3groupId>
                <artifactId>xpp3_minartifactId>
                <version>1.1.4cversion>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    基础使用demo

    以下分析均采用此demo

    JavaBean对象

    写两个JavaBean

    package demo;
    
    public class Score {
        private String subject;
        private int point;
    
        public Score(String subject, int point) {
            this.subject = subject;
            this.point = point;
        }
    
        public String getSubject() {
            return subject;
        }
    
        public void setSubject(String subject) {
            this.subject = subject;
        }
    
        public int getPoint() {
            return point;
        }
    
        public void setPoint(int point) {
            this.point = point;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    package demo;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Student {
        private String name;
        private String id;
        private List<Score> scores = new ArrayList<Score>();
    
        public Student(String name, String id) {
            this.name = name;
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Score> getScores() {
            return scores;
        }
    
        public void setScores(List<Score> scores) {
            this.scores = scores;
        }
    
        public void addScore(Score score){
            scores.add(score);
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    代码

    package demo;
    
    import com.thoughtworks.xstream.XStream;
    
    public class Demo {
        public static void main(String[] args) {
            Score math = new Score("math", 99);
            Student student = new Student("Bob", "114514");
            student.addScore(math);
    
            XStream xStream = new XStream();
    
    		// 序列化
            String string = xStream.toXML(student);
            System.out.println(string);
    
    		// 反序列化
            Student student1 = (Student) xStream.fromXML(string);
            System.out.println(student1.toString()+ " " +student1.getName() + " " +student1.getScores().get(0).getSubject());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    序列化结果

    <demo.Student>
      <name>Bobname>
      <id>114514id>
      <scores>
        <demo.Score>
          <subject>mathsubject>
          <point>99point>
        demo.Score>
      scores>
    demo.Student>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    反序列化结果

    demo.Student@5f9d02cb Bob math
    
    • 1

    同一对象序列化和反序列化的一致性

    对于相同XStream,反复序列化和反序列化同一个对象,结果都是一致的

            XStream xStream = new XStream();
            String string = xStream.toXML(student);
            System.out.println(string);
            
            Student student1 = (Student) xStream.fromXML(string);
            String string1 = xStream.toXML(student1);
            
            System.out.println(string.equals(string1));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    进阶操作

    给标签起别名

    		XStream xStream = new XStream();
            xStream.alias("StuInfo", Student.class);
            String string = xStream.toXML(student);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    将对象属性转化为XML标签属性

            XStream xStream = new XStream();
            xStream.useAttributeFor(Student.class, "name");
            xStream.useAttributeFor(Student.class, "id");
            String string = xStream.toXML(student);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    添加隐式集合

    对于集合的序列化和反序列化,告知XStream核心能够简化操作

            XStream xStream = new XStream();
            xStream.addImplicitCollection(Student.class, "scores");xStream.useAttributeFor(Student.class, "name");
            String string = xStream.toXML(student);
    
    • 1
    • 2
    • 3

    实际体现就是:给demo对象再添加一个score

    在这里插入图片描述
    此时List的标签就被自动忽略了,正常应该是 ...

    在这里插入图片描述
    同样的反序列化时候直接多条合并写入即可,XStream核心已经知晓此处是一个隐式的集合

    如果没有事先声明此处是隐式集合,只把多条集合元素合并写入会抛错

    设置变量不被序列化

            XStream xStream = new XStream();
            xStream.omitField(Student.class, "scores");
            String string = xStream.toXML(student);
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    XStream核心结构图

    原链接见参考

    浅析XStream序列化操作源码

    调用toXML()时,首先new了一个StringWriter作为输出

    在这里插入图片描述
    之后这个StringWriter转换成了一个PrettyPrintWriter用于优化分层结构的XML输出,然后进入marshal方法

    在这里插入图片描述
    传入convertLookup和mapper

    在这里插入图片描述
    原链接见参考
    接下来就是新建树编组器,然后开始编组

    在这里插入图片描述
    原链接见参考
    首先进行头节点也就是整个类最外层的XML编组,然后convertAnother方法开始转换对象

    在这里插入图片描述
    来到doMarshal(),首先调用反射获取属性

    在这里插入图片描述
    然后放到List中

    在这里插入图片描述
    如果涉及可迭代对象,对内部有处理,流程也是调用marshal()到convertAnother()到visitSerializableFields()

    在这里插入图片描述
    在这里插入图片描述

    层次化体现在使用栈和路径的概念来处理包含关系

    在这里插入图片描述

    回到doMarshal(),当所有属性都添加到fields中,就开始写入writer了,一个迭代器循环

    在这里插入图片描述
    调用writeField序列化属性,这里传入了五个参数:属性名称、别名、类型、所属类、值

    在这里插入图片描述
    首先写入左边的XML标签

    在这里插入图片描述
    然后调用marshallField写入值,最后再写入右XML标签

    在这里插入图片描述
    写入值时单独提取了出来,也就是说无论是键还是值,序列化操作都是提取成item转换,只是在标签左右尖括号等处有特殊额外写入处理

    在这里插入图片描述
    写入值最终调用了PrettyPrintWriter.setValue

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    浅析XStream反序列化操作源码

    反序列化的流程大概与序列化一致

    调用MarshallingStrategy.unmarshal解组
    在这里插入图片描述
    首先调用HierarchicalStreams.readClassType获取反序列化的类,然后调用convertAnother进行复原

    在这里插入图片描述
    获取converter转换器,进去看看细节

    在这里插入图片描述
    对于普通Bean,默认是ReflectionConverter,从缓存中获取的;如果缓存没有下面就会查找合适的converter

    在这里插入图片描述
    有很多个converter
    在这里插入图片描述
    值得注意的是,有两个特殊converter:一般Bean是反射converter,而实现了serializable接口的类走的是serializableConverter

    在这里插入图片描述
    serializableConverter的介绍:看介绍是可以调用readObject方法模拟正常反序列化流程

    在这里插入图片描述
    往后来到AbstractReflectionConverter.unmarshal,调用instantiateNewInstance新建反序列化类的实例,然后调用doUnmarshal给它添加所有的属性参数

    在这里插入图片描述

    参考

    https://x-stream.github.io/index.html
    https://github.com/jakingting/Xtream-jar/tree/master/XStreamUML
    https://blog.csdn.net/u014565127/article/details/104419528
    https://www.jianshu.com/p/387c568faf62

    欢迎关注我的CSDN博客 :@Ho1aAs
    版权属于:Ho1aAs
    本文链接:https://ho1aas.blog.csdn.net/article/details/126250860
    版权声明:本文为原创,转载时须注明出处及本声明

  • 相关阅读:
    嵌入式开发:估算电池寿命的7个技巧
    开源AI搜索平台Search4All
    NewStarCTF2023 Reverse方向Week3 ez_chal WP
    day3 数1 函数
    一文带你理解@RefreshScope注解实现动态刷新原理
    [Python]dict字典排序事例
    Java虚拟机(JVM)面试专题(初级程序员P6)
    JDK:字体大小是如何生效的
    关于OCR文字识别的坑(64位Python专属)
    Java中的IO流的缓冲流
  • 原文地址:https://blog.csdn.net/Xxy605/article/details/126250860