Java 与JSON(fastJosn常用方法)

Java 与JSON

在工作中有很多的文件格式都是采用Json格式传输数据。当我们接受到Json格式的数据需要把json数据转成对象进行数据处理或者是把数据转换json格式进行数据输出。Java把对象转换json,或者把json转换成对象都有哪些工具库呢??

json介绍

JSON(Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

JSON是一个标记符的序列。这套标记符包含六个构造字符字符串数字和三个字面名

JSON是一个序列化的对象数组

JSON 的语法规则十分简单,可称得上“优雅完美”,总结起来有

  • 数组(Array)用方括号(“[]”)表示。
  • 对象(0bject)用大括号(“{}”)表示。
  • 名称/值对(name/value)组合成数组和对象。
  • 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组。
  • 并列的数据之间用逗号(“,”)分隔
{
	"name": "xdr630",
	"favorite": "programming"
}

json类库

json不管是在Web开发还是服务器开发中是相当常见的数据传输格式,一般情况我们对于JSON解析构造的性能并不需要过于关心,除非是在性能要求比较高的系统。

目前对于Java开源的JSON类库有很多种,下面我们取4个常用的JSON库进行性能测试对比, 同时根据测试结果分析如果根据实际应用场景选择最合适的JSON库。

这4个JSON类库分别为:Gson,FastJson,Jackson,Json-lib

选择一个合适的JSON库要从多个方面进行考虑:

  1. 字符串解析成JSON性能
  2. 字符串解析成JavaBean性能
  3. JavaBean构造JSON性能
  4. 集合构造JSON性能
  5. 易用性

先简单介绍下四个类库的身份背景

Gson

项目地址:https://github.com/google/gson

Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用。 Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。 在使用这种对象转换之前,需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。 类里面只要有get和set方法,Gson完全可以实现复杂类型的json到bean或bean到json的转换,是JSON解析的神器。

FastJson

项目地址:https://github.com/alibaba/fastjson

Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。无依赖,不需要例外额外的jar,能够直接跑在JDK上。 FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。 FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。

Jackson

项目地址:https://github.com/FasterXML/jackson

Jackson是当前用的比较广泛的,用来序列化和反序列化json的Java开源框架。Jackson社区相对比较活跃,更新速度也比较快, 从Github中的统计来看,Jackson是最流行的json解析器之一,Spring MVC的默认json解析器便是Jackson。

Jackson优点很多:

  1. Jackson 所依赖的jar包较少,简单易用。
  2. 与其他 Java 的 json 的框架 Gson 等相比,Jackson 解析大的 json 文件速度比较快。
  3. Jackson 运行时占用内存比较低,性能比较好
  4. Jackson 有灵活的 API,可以很容易进行扩展和定制。

目前最新版本是2.9.4,Jackson 的核心模块由三部分组成:

  1. jackson-core 核心包,提供基于”流模式”解析的相关 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
  2. jackson-annotations 注解包,提供标准注解功能;
  3. jackson-databind 数据绑定包,提供基于”对象绑定” 解析的相关 API( ObjectMapper )和”树模型” 解析的相关 API(JsonNode);基于”对象绑定” 解析的 API 和”树模型”解析的 API 依赖基于”流模式”解析的 API。

Json-lib

项目地址:http://json-lib.sourceforge.net/index.html

json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,对于复杂类型的转换,json-lib对于json转换成bean还有缺陷, 比如一个类里面会出现另一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。json-lib在功能和性能上面都不能满足现在互联网化的需求。

比测试

1、pom依赖

<!-- Json libs-->
<dependency>
    <groupId>net.sf.json-lib</groupId>
    <artifactId>json-lib</artifactId>
    <version>2.4</version>
    <classifier>jdk15</classifier>
</dependency>
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.14</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.4</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.4</version>
</dependency>

测试比较方法

https://blog.csdn.net/lin443514407lin/article/details/85262479

Fastjson

Fastjson 是一个 Java 库,可用于将 Java 对象转换为其 JSON 表示。它还可用于将 JSON 字符串转换为等效的 Java 对象。Fastjson 可以处理任意 Java 对象,包括您没有源代码的预先存在的对象。

Json是一种轻量级的数据交换格式,采用一种“键:值”对的文本格式来存储和表示数据,在系统交换数据过程中常常被使用,是一种理想的数据交换语言。在使用Java做Web开发时,不可避免的会遇到Json的使用。

特点

  • 在服务端和安卓客户端提供最佳性能
  • 提供简单的 toJSONString() 和 parseObject() 方法来将 Java 对象转换为 JSON,反之亦然
  • 允许预先存在的不可修改对象与 JSON 相互转换
  • 对 Java 泛型的广泛支持
  • 允许对象的自定义表示
  • 支持任意复杂的对象(具有深层继承层次和泛型类型的广泛使用

Fastjson 源码地址:https://github.com/alibaba/fastjson

Fastjson 中文 Wiki:https://github.com/alibaba/fastjson/wiki/Quick-Start-CN

maven库地址:https://mvnrepository.com/artifact/com.alibaba/fastjson/2.0.14

优秀文章:

http://i.kimmking.cn/2017/06/06/json-best-practice/

https://www.runoob.com/json/json-tutorial.html

开发者:温绍锦

1、环境配置

你可以在 maven 中央仓库中直接下载:

https://repo1.maven.org/maven2/com/alibaba/fastjson/

或者配置 maven 依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>x.x.x</version>
</dependency>

其中 x.x.x 是版本号,根据需要使用特定版本,建议使用最新版本。

中央仓库:https://mvnrepository.com/artifact/com.alibaba/fastjson

2、应用

https://www.runoob.com/w3cnote/fastjson-intro.html

准备

package com.bean;

import com.alibaba.fastjson.annotation.JSONField;

import java.util.Date;

public class Person {
    @JSONField(name = "AGE",serialize=false)//自定义转换 :nanm定义上的key    serialize:指定字段不序列化  默认 fastjson序列化根据 fieldName 的字母序进行序列化
    private int age;

    //默认j变量名为json的key
    private String fullName;

    @JSONField(name="DATE OF BIRTH", format="dd/MM/yyyy", ordinal = 3) //自定义转换  format:用于格式化date属性   ordinal:指定字段的顺序 默认0
    private Date dateOfBirth;

    public Person(int age, String fullName, Date dateOfBirth) {
        this.age = age;
        this.fullName = fullName;
        this.dateOfBirth = dateOfBirth;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
}

2.1 创建 JSON 对象

创建 JSON 对象非常简单,只需使用 JSONObject(fastJson提供的json对象) 和 JSONArray(fastJson提供json数组对象) 对象即可。

我们可以把JSONObject 当成一个 Map<String,Object> 来看,只是 JSONObject 提供了更为丰富便捷的方法,方便我们对于对象属性的操作。

public class JSONObject 
    extends JSON 
    implements Map<String, Object>, Cloneable, Serializable, InvocationHandler 

JSONArray 当做一个 List,可以把 JSONArray 看成 JSONObject 对象的一个集合

public class JSONArray 
    extends JSON 
    implements List<Object>, Cloneable, RandomAccess, Serializable

由于 JSONObject 和 JSONArray 继承了 JSON,所以说也可以直接使用两者对 JSON 格式字符串与 JSON 对象及 javaBean 之间做转换,不过为了避免混淆我们还是使用 JSON。

   // JSONObject和JSONArray转换
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < 2; i++) {
            JSONObject jsonObject33 = new JSONObject();
            jsonObject33.put("AGE", 10);
            jsonObject33.put("FULL NAME", "Doe " + i);
            jsonObject33.put("DATE OF BIRTH", "2016/12/12 12:12:12");
            jsonArray.add(jsonObject33);
        }
        String jsonOutputz = jsonArray.toJSONString();
        System.out.println("JSONObject和JSONArray转换:"+jsonOutputz);

        /**
         * [
         *   {
         *     "DATE OF BIRTH": "2016/12/12 12:12:12",
         *     "FULL NAME": "Doe 0",
         *     "AGE": 10
         *   },
         *   {
         *     "DATE OF BIRTH": "2016/12/12 12:12:12",
         *     "FULL NAME": "Doe 1",
         *     "AGE": 10
         *   }
         * ]
         */

2.2 对象转换为 JSON

Java 对象转换换为 JSON 对象:JSON.toJSONString()

案例:

import com.alibaba.fastjson.JSON;
import com.bean.Person;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class testjson {
    private List<Person> listOfPersons = new ArrayList<Person>();
    //执行@test前执行
    @Before
    public void setUp() {
        listOfPersons.add(new Person(15, "John Doe", new Date()));
        listOfPersons.add(new Person(20, "Janette Doe", new Date()));
    }

    @Test
    public void whenJavaList_thanConvertToJsonCorrect() {
        //JSON.toJSONString()   Java 对象转换换为 JSON 对象
        String jsonString = JSON.toJSONString(new Person(15, "John Doe", new Date()));
        System.out.println("Person类转jsonString:"+jsonString);
        String jsonOutput= JSON.toJSONString(listOfPersons);
        System.out.println("list<Person类>:"+jsonOutput);

        //
    }
}

运行结果如下:

Person类转jsonString:{"fullName":"John Doe","DATE OF BIRTH":"05/12/2021"}

list<Person>:[{"fullName":"John Doe","DATE OF BIRTH":"05/12/2021"},{"fullName":"Janette Doe","DATE OF BIRTH":"05/12/2021"}]

2.3 JSON 转换为对象

JSON.parseObject

实例类

package com.bean;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import java.util.Date;

public class Person {
    @JSONField(name = "AGE")//自定义转换 :nanm定义上的key    serialize=false serialize:指定字段不序列化  默认 fastjson序列化根据 fieldName 的字母序进行序列化
    private int age;

    //默认j变量名为json的key
    private String fullName;

    @JSONField(name="DATE OF BIRTH",ordinal = 3,format = "dd/MM/yyyy" ,deserialize=false) //自定义转换   format = "dd/MM/yyyy"  format:用于格式化date属性   ordinal:指定字段的顺序 默认0
    @JsonFormat(shape = JsonFormat.Shape.STRING,pattern="yyyy-MM-dd HH:mm:ss")
    private Date dateOfBirth;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", fullName='" + fullName + '\'' +
                ", dateOfBirth=" + dateOfBirth +
                '}';
    }

    public Person(int age, String fullName, Date dateOfBirth) {
        this.age = age;
        this.fullName = fullName;
        this.dateOfBirth = dateOfBirth;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
}

转换

//JSON转换为Java,时间未格式化
String zhO = "{\"AGE\":20,\"fullName\":\"John\",\"DATE OF BIRTH\":1638681972980}";
Person newPerson = JSON.parseObject(zhO, Person.class);
System.out.println("转Person::"+newPerson);

//Json转java,格式化时间:yyyy-MM-dd HH:mm:ss
// 实例date类上 @JsonFormat(shape = JsonFormat.Shape.STRING,pattern="yyyy-MM-dd HH:mm:ss")
String sss = "{\"AGE\":20,\"fullName\":\"John\",\"DATE OF BIRTH\":\"2020-01-08 22:41:54\"}";
System.out.println("转化数据:"+sss);
Person newPerson2 = JSON.parseObject(sss, Person.class);
System.out.println("转Person2::"+newPerson2);

2.4 json转换List集合

JSON.paresArray()

//	JSON类的静态方法,parseArray
//	传递Json格式字符串,传递转换后的集合的泛型的Class对象
String listString="[{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"},{\"address\":\"北京市\",\"age\":20,\"id\":1,\"name\":\"张三\"}]";

List<Student> students = JSON.parseArray(listString, Student.class);

2.5 json转换为Map集合

//	JSON类的静态方法 parseObject
//	传递要反序列化的Json字符串、要序列化的类型接口
String jsonString="{\"address\":\"北京市\",\"age\":20,\"email\":\"zs@sina.com\",\"id\":1,\"name\":\"张三\"}";
Map<String, String> map = JSON.parseObject(jsonString, new TypeReference<Map<String, String>>() {});

2.6 获取json某个值

  JSONObject object1 = new JSONObject();
        //1.在JSONObject对象中放入键值对
        object1.put("name", "张三");
        object1.put("name1", "张三1");
        object1.put("name2", "张三2");
        System.out.println(object1);
        //2.根据key获取value
        String name = (String) object1.get("name");
        System.out.println(name)

3、固定枚举注解

1、SerializerFeature枚举

该枚举支持序列化的一些特性数据定义。

名称描述
QuoteFieldNames输出key时是否使用双引号,默认为true
UseSingleQuotes使用单引号而不是双引号,默认为false
WriteMapNullValue是否输出值为null的字段,默认为false
WriteEnumUsingToStringEnum输出name()或者original,默认为false
WriteEnumUsingName用枚举name()输出
UseISO8601DateFormatDate使用ISO8601格式输出,默认为false
WriteNullListAsEmptyList字段如果为null,输出为[],而非null
WriteNullStringAsEmpty字符类型字段如果为null,输出为”“,而非null
WriteNullNumberAsZero数值字段如果为null,输出为0,而非null
WriteNullBooleanAsFalseBoolean字段如果为null,输出为false,而非null
SkipTransientField如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
SortField按字段名称排序后输出。默认为false
(过期)WriteTabAsSpecial把\t做转义输出,默认为false
PrettyFormat结果是否格式化,默认为false
WriteClassName序列化时写入类型信息,默认为false。反序列化时需用到
DisableCircularReferenceDetect消除对同一对象循环引用的问题,默认为false
WriteSlashAsSpecial对斜杠’/’进行转义
BrowserCompatible将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
WriteDateUseDateFormat全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
(过期)DisableCheckSpecialChar一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false

WriteMapNullValue

//	{"age":10,"id":0,"name":"张三"}
String s = JSON.toJSONString(stu);

//	{"address":null,"age":10,"email":null,"id":null,"name":"张三"}
String s = JSON.toJSONString(stu, SerializerFeature.WriteMapNullValue);

WriteNullNumberAsZero

//	{"age":10,"id":0,"name":"张三"}
String s = JSON.toJSONString(stu);

//	{"age":10,"id":0,"name":"张三"}
String s = JSON.toJSONString(stu, SerializerFeature.WriteNullNumberAsZero);

WriteNullStringAsEmpty

//	{"age":10,"id":0,"name":"张三"}
String s = JSON.toJSONString(stu);

//	{"address":"","age":10,"email":"","name":"张三"}
String s = JSON.toJSONString(stu, SerializerFeature.WriteNullStringAsEmpty);

WriteNullBooleanAsFalse

//	{"age":10,"id":0,"name":"张三"}
String s = JSON.toJSONString(stu);

//	{"age":10,"isBoolean":false,"name":"张三"}
String s = JSON.toJSONString(stu, SerializerFeature.WriteNullBooleanAsFalse);

WriteDateUseDateFormat

{"age":10,"date":1652783554404,"name":"张三"}
String s = JSON.toJSONString(stu);

  {"age":10,"date":"2022-05-17 18:31:59","name":"张三"}
String s = JSON.toJSONString(stu, SerializerFeature.WriteDateUseDateFormat);

PrettyFormat

JSON.toJSONString(stu, SerializerFeature.WriteDateUseDateFormat,SerializerFeature.PrettyFormat);
/**
{
	"age":10,
	"date":"2022-05-17 18:37:11",
	"name":"张三"
}

*/

2、@JSonField注解

该注解作用于方法上,字段上和参数上.可在序列化和反序列化时进行特性功能定制.

  • 注解属性 : name 序列化后的名字
  • 注解属性 : ordinal序列化后的顺序
  • 注解属性 : format 序列化后的格式
  • 注解属性 : serialize 是否序列化该字段
  • 注解属性 : deserialize 是否反序列化该字段
  • 注解属性 : serialzeFeatures 序列化时的特性定义(等同于SerializerFeature枚举)
  • 注解属性:label给属性打上标签, 相当于给属性进行了分组
  • 注解属性:serializeUsing设置属性的序列化类
  • 注解属性:deserializeUsing设置属性的反序列化类
@Data
public class Student {

    //  name 序列化后的名字
    @JSONField(name = "myName")
    private String name;
    //  ordinal序列化后的顺序
    @JSONField(ordinal = 2)
    private Integer age;

    //  ordinal序列化后的顺序
    @JSONField(ordinal = 1)
    private String address;
    //  serialize 是否序列化该字段
    @JSONField(serialize = false)
    private String email;

    //  deserialize 是否反序列化该字段
    @JSONField(deserialize = false)
    private Boolean isBoolean;

    //  序列化时的特性定义
    @JSONField(serialzeFeatures = {SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.PrettyFormat})
    private String desc;

    //  format 序列化后的格式
    @JSONField(format = "YYYY-MM-dd")
    private Date date;
}

3、@JSonType注解

@JSonType与@JSONField产生冲突时,@JSONField优先级高

该注解作用于类上,对该类的字段进行序列化和反序列化时的特性功能定制。

  • 注解属性 : includes 要被序列化的字段。
  • 注解属性 : orders 序列化后的顺序。
  • 注解属性 : serialzeFeatures 序列化时的特性定义(等同于SerializerFeature枚举)。
@Data
@JSONType(
	//	includes 要被序列化的字段
        includes = {"name", "age", "address"},
  //	orders 序列化后的顺序.
        orders = {"age", "name", "address"},
  //	serialzeFeatures 序列化时的特性定义
        serialzeFeatures = {SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.PrettyFormat})
public class Student {

    private String name;

    private Integer age;
//  ordinal序列化后的顺序
    @JSONField(ordinal = 1)
    private String address;
}

4、使用 ContextValueFilter 配置 JSON 转换

在某些场景下,对Value做过滤,需要获得所属JavaBean的信息,包括类型、字段、方法等。在fastjson-1.2.9中,提供了ContextValueFilter,类似于之前版本提供的ValueFilter,只是多了BeanContext参数可用。

//过滤
String jsonOutputaf = JSON.toJSONString(listOfPersons);
System.out.println("jsonOutputaf>>>>>:"+jsonOutputaf);
ContextValueFilter valueFilter = new ContextValueFilter() {
    @Override
    public Object process(BeanContext beanContext, Object o, String name, Object value) {
        if (name.equals("DATE OF BIRTH")) {  //key =DATE OF BIRTH  改为NOT TO DISCLOSE
            return "NOT TO DISCLOSE";
        }
        if (value.equals("John Doe")) {  //值等于John Doe是大写JOHN DOE
            System.out.println(((String) value).toUpperCase());
            return ((String) value).toUpperCase();
        }else {
            return value;
        }
    }
};
String jsonOutputFilter = JSON.toJSONString(listOfPersons, valueFilter);

System.out.println("jsonOutputFilter::::"+jsonOutputFilter);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值