2.java程序员必知必会类库之json解析库

前言

百度百科解释

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

在当今世界的web服务的数据交互中,JSON已经取代了XML,成为从客户端到服务器传送信息的首选协议。有一个好消息和一个坏消息。坏消息是JDK没有提供JSON库。好消息是有许多优秀的第三方库可以用来解析和创建JSON消息,如 fastjson和 Gson

fastjson

1.介绍

Git地址: https://github.com/alibaba/fastjson
Wiki:https://github.com/alibaba/fastjson/wiki
FAQ:https://github.com/alibaba/fastjson/wiki/常见问题

2. 使用

2.1. pom依赖引入

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.83version>
dependency>

2.2 api使用

2.2.1 序列化对象转字符串
public class User {

    private String username;

    private Date birthday;

    private int sex;

//省略getset tostring方法
}
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");

User user2=new User();
user2.setUsername("wangpeng");
user2.setSex(0);
user2.setBirthday(new Date());

List<User> userList=new ArrayList<User>();
userList.add(user);
userList.add(user2);
System.out.println(JSON.toJSONString(userList));
//[{"birthday":1681351631631,"sex":1,"username":"liming"},{"birthday":1681351631631,"sex":0,"username":"wangpeng"}]

String str = JSONObject.toJSONString(user);
System.out.println(str);
//{"birthday":1681350602343,"sex":1,"username":"liming"}

这里jsonobject 和 JSONArray 实际继承的都是抽象父类JSON,两个类的很多方法实际都用的是JSON的方法,比如toJSONString

2.2.2 反序列化字符串转对象
String str="{\"birthday\":1681350739299,\"sex\":1,\"username\":\"liming\"}";
User user = JSONObject.parseObject(str, User.class);
System.out.println(user.toString());
//User{username='liming', birthday=Thu Apr 13 09:52:19 CST 2023, sex=1}

String str2="[{\"birthday\":1681351631631,\"sex\":1,\"username\":\"liming\"},{\"birthday\":1681351631631,\"sex\":0,\"username\":\"wangpeng\"}]";
List<User> users = JSONArray.parseArray(str2, User.class);
System.out.println(users);
//[User{username='liming', birthday=Thu Apr 13 10:07:11 CST 2023, sex=1}, User{username='wangpeng', birthday=Thu Apr 13 10:07:11 CST 2023, sex=0}]

3.注意事项

3.1 版本问题

之前fastjson出现漏洞,为此,出于安全考虑,需要升级公司fastjson版本到1.2.83 以上,关于漏洞更多信息,可网上找相关内容深入了解

3.2 循环引用的问题

当进行toJSONString的时候,默认如果重用对象的话,会使用引用的方式进行引用对象。,详见下面代码示例

A a = new A();
B b = new B();
a.setB(b);
ArrayList<Object> objects = new ArrayList<Object>();
objects.add(a);
//这里和a重用b对象
objects.add(b);
String string = JSON.toJSONString(objects);
//可以看到序列化出来的数据带引用
System.out.println(string); //[{"b":{}},{"$ref":"$[0].b"}]
JSONArray array = JSON.parseArray(string);
//反序列化也可以看到实际引用对象地址是一样的
boolean isTheSameObject = array.getJSONObject(0).getJSONObject("b") == array.getJSONObject(1);
System.out.println(isTheSameObject);//true
//去除循环依赖检测
String deleteRefrenceStr = JSON.toJSONString(objects, SerializerFeature.DisableCircularReferenceDetect);
System.out.println(deleteRefrenceStr); //[{"b":{}},{}]
// 去除循环依赖后反序列化,可以看到生成的对象与原来的没有关系
JSONArray array2=JSON.parseArray(deleteRefrenceStr);
System.out.println(array2.getJSONObject(0).getJSONObject("b") == array2.getJSONObject(1));
//false

3.3 常见注解使用

3.3.1 JSONField注解

该注解主要用于在序列化和反序列化的时候,对我们要处理的对象做一些自己想要的定制化配置,而不是用通用的处理,注解属性如下:

package com.alibaba.fastjson.annotation;
public @interface JSONField {
    // 配置序列化和反序列化的顺序,1.1.42版本之后才支持
    int ordinal() default 0;

     // 指定字段的名称
    String name() default "";

    // 指定字段的格式,对日期格式有用
    String format() default "";

    // 是否序列化
    boolean serialize() default true;

    // 是否反序列化
    boolean deserialize() default true;
}

下面通过几个简单的例子展示如何使用该注解
注意:1、若属性是私有的,必须有set*方法。否则无法反序列化。

 public class A {
      @JSONField(name="ID")
      private int id;
 
      @JSONField(name="ID")
      public int getId() {return id;}
      @JSONField(name="ID")
      public void setId(int value) {this.id = id;}
      
     // 配置date序列化和反序列使用yyyyMMdd日期格式
      @JSONField(format="yyyyMMdd")
      public Date date;
      // 使用serialize/deserialize指定字段不序列化
 	  @JSONField(serialize=false)
      public Date birthday;
	  //缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本
   	  @JSONField(ordinal = 3)
      private int f0;
      @JSONField(ordinal = 2)
      private int f1;
      @JSONField(ordinal = 1)
      private int f2;
 }
3.3.1.1 使用serializeUsing制定属性的序列化类

在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化,

public static class Model {
    @JSONField(serializeUsing = ModelValueSerializer.class)
    public int value;
}

public static class ModelValueSerializer implements ObjectSerializer {
    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
                      int features) throws IOException {
        Integer value = (Integer) object;
        String text = value + "元";
        serializer.write(text);
    }
}

Model model = new Model();
model.value = 100;
String json = JSON.toJSONString(model);
Assert.assertEquals("{\"value\":\"100元\"}", json);
3.3.2 JSONType注解

在1.2.14版本之后,fastjson支持通过JSONType配置定制序列化的ObjectSerializer。使用如下

@JSONType(serializer=ModelSerializer.class)
public static class Model {
    public int id;
}

public static class ModelSerializer implements ObjectSerializer {

    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
                      int features) throws IOException {
        Model model = (Model) object;
        SerializeWriter out = serializer.getWriter();
        out.writeFieldValue('{', "ID", model.id);
        out.write('}');
    }
}
Model model = new Model();
model.id = 1001;
String text = JSON.toJSONString(model);
Assert.assertEquals("{\"ID\":1001}", text);

3.4 序列化特性使用

上面有提到序列化去除循环依赖的使用特性,fastjson 也提供了很多其他序列化方式,这些序列化方式可以一起组合使用。下面代码我是从fastjson 源码里拷贝过来的。
通过英文名基本就能猜到使用相应特性的结果,这里就不一一赘述。

public enum SerializerFeature {
QuoteFieldNames,
UseSingleQuotes,
WriteMapNullValue,
WriteEnumUsingToString,
WriteEnumUsingName,
UseISO8601DateFormat,
WriteNullListAsEmpty,
WriteNullStringAsEmpty,
WriteNullNumberAsZero,
WriteNullBooleanAsFalse,
SkipTransientField,
SortField,
/** @deprecated */
@Deprecated
WriteTabAsSpecial,
PrettyFormat,
WriteClassName,
DisableCircularReferenceDetect,
WriteSlashAsSpecial,
BrowserCompatible,
WriteDateUseDateFormat,
NotWriteRootClassName,
/** @deprecated */
DisableCheckSpecialChar,
BeanToArray,
WriteNonStringKeyAsString,
NotWriteDefaultValue,
BrowserSecure,
IgnoreNonFieldGetter,
WriteNonStringValueAsString,
IgnoreErrorGetter,
WriteBigDecimalAsPlain,
MapSortField;
}

3.5 自定义序列化与反序列化

3.5.1 自定义序列化

参考官网,不再赘述

3.5.2 自定义反序列化

参考官网,不再赘述

4.与spring结合

参考官网介绍

Gson

1.介绍

GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。GSON笔者使用不多,这里只做简单介绍

2. 使用

2.1 pom坐标


<dependency>
  <groupId>com.google.code.gsongroupId>
  <artifactId>gsonartifactId>
  <version>2.8.5version>
dependency>

2.2 api使用

2.2.1 对象序列化与反序列化demo

User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");
//序列化  基本类型有默认值,包装类不解析
String str = new Gson().toJson(user);
System.out.println(str);
//{"username":"liming","birthday":"Apr 13, 2023 3:37:26 PM","sex":1}
User user2=new User();
user2.setUsername("wangpeng");
user2.setBirthday(new Date());
System.out.println(new Gson().toJson(user2));
//{"username":"wangpeng","birthday":"Apr 13, 2023 3:39:13 PM","sex":0}

//反序列化
User userDeseri = new Gson().fromJson(str, User.class);
System.out.println(userDeseri);
//User{username='liming', birthday=Thu Apr 13 15:40:48 CST 2023, sex=1}
2.2.2 集合序列化与反序列化demo
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");

User user2=new User();
user2.setUsername("wangpeng");
user2.setBirthday(new Date());

List<User> userList=new ArrayList<User>();
userList.add(user);
userList.add(user2);
//集合序列化
String toJsonStr = new Gson().toJson(userList);
System.out.println(toJsonStr);
//[{"username":"liming","birthday":"Apr 13, 2023 3:48:50 PM","sex":1},{"username":"wangpeng","birthday":"Apr 13, 2023 3:48:50 PM","sex":0}]
//集合反序列化
Type type = new TypeToken<ArrayList<User>>(){}.getType();
List<User> users = new Gson().fromJson(toJsonStr, type);
System.out.println(users);
//[User{username='liming', birthday=Thu Apr 13 15:48:50 CST 2023, sex=1}, User{username='wangpeng', birthday=Thu Apr 13 15:48:50 CST 2023, sex=0}]

3.注意事项

3.1 指定序列化和反序列化字段名称

通过该注解,可以在序列化和反序列化的时候调整属性名称

public class User {
    @SerializedName("testuser")
    private String username;
    private Date birthday;
    private int sex;
}
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");
String str = new Gson().toJson(user);
//{"testuser":"liming","birthday":"Apr 13, 2023 4:03:08 PM","sex":1}

3.2 忽略解析某个值

使用transient关键字修饰的属性,不参与序列化

public class User {

    private String username;
    private Date birthday;
    private transient int sex;
}
User user = new User();
user.setBirthday(new Date());
user.setSex(1);
user.setUsername("liming");
String str = new Gson().toJson(user);
//{"username":"liming","birthday":"Apr 13, 2023 3:56:22 PM"}

参考文献:
阿里巴巴fastjson github

你可能感兴趣的:(java程序员必知必会类库,java,json,fastjson,Gson)