https://www.hoshino.asia/archives/hutool

概述

为何集成

JSON在现在的开发中做为跨平台的数据交换格式已经慢慢有替代XML的趋势(比如RESTful规范),我想大家在开发中对外提供接口也越来越多的使用JSON格式。

不可否认,现在优秀的JSON框架非常多,我经常使用的像阿里的FastJSON,Jackson等都是非常优秀的包,性能突出,简单易用。Hutool开始也并不想自己写一个JSON,但是在各种工具的封装中,发现JSON已经不可或缺,因此将json.org官方的JSON解析纳入其中,进行改造。在改造过程中,积极吸取其它类库优点,优化成员方法,抽象接口和类,最终形成Hutool-json。

介绍

Hutool-json的核心类只有两个:

  • JSONObject

  • JSONArray

这与其它JSON包是类似的,与此同时,还提供一个JSONUtil工具类用于简化针对JSON的各种操作和转换。

除了核心类,还提供了一些辅助类用于实现特定功能:

  • JSONSupport Bean类继承此对象即可无缝转换为JSON或JSON字符串。同时实现了toString()方法可将当前对象输出为JSON字符串。

  • XML 提供JSON与XML之间的快速转换,同时JSONUtil中有相应静态封装。

  • JSON JSONObject和JSONArray共同实现的接口类,JSONUtil.parse方法默认返回此对象(因为不知道是JSON对象还是JSON数组),然后可以根据实际类型判断后转换对象类型。

与FastJSON类似,JSONObject实现了Map接口,JSONArray实现了List接口,这样我们便可以使用熟悉的API来操作JSON。

在JSON中,Hutool封装了getXXX方法,支持大部分内置类型的值获取操作。比如:

JSONObject json1 = JSONUtil.createObj();
json1.getStr("key");
json1.getInt("key");
json1.getLong("key");
json1.getDouble("key");
json1.getBigDecimal("key");

这些成员方法的加入,可以省掉大量的类型转换代码,大大提高JSON的操作简便性。

JSON工具-JSONUtil

介绍

JSONUtil是针对JSONObject和JSONArray的静态快捷方法集合,在之前的章节我们已经介绍了一些工具方法,在本章节我们将做一些补充。

使用

JSON字符串创建

JSONUtil.toJsonStr可以将任意对象(Bean、Map、集合等)直接转换为JSON字符串。 如果对象是有序的Map等对象,则转换后的JSON字符串也是有序的。

SortedMap<Object, Object> sortedMap = new TreeMap<Object, Object>() {
	private static final long serialVersionUID = 1L;
	{
	put("attributes", "a");
	put("b", "b");
	put("c", "c");
}};

JSONUtil.toJsonStr(sortedMap);

结果:

{"attributes":"a","b":"b","c":"c"}

如果我们想获得格式化后的JSON,则:

JSONUtil.toJsonPrettyStr(sortedMap);

结果:

{
    "attributes": "a",
    "b": "b",
    "c": "c"
}

JSON字符串解析

String html = "{\"name\":\"Something must have been changed since you leave\"}";
JSONObject jsonObject = JSONUtil.parseObj(html);
jsonObject.getStr("name");

XML字符串转换为JSON

String s = "<sfzh>123</sfzh><sfz>456</sfz><name>aa</name><gender>1</gender>";
JSONObject json = JSONUtil.parseFromXml(s);

json.get("sfzh");
json.get("name");

JSON转换为XML

final JSONObject put = JSONUtil.createObj()
		.set("aaa", "你好")
		.set("键2", "test");

// <aaa>你好</aaa><键2>test</键2>
final String s = JSONUtil.toXmlStr(put);

JSON转Bean

我们先定义两个较为复杂的Bean(包含泛型)

@Data
public class ADT {
	private List<String> BookingCode;
}

@Data
public class Price {
	private List<List<ADT>> ADT;
}
String json = "{\"ADT\":[[{\"BookingCode\":[\"N\",\"N\"]}]]}";

Price price = JSONUtil.toBean(json, Price.class);

// N
price.getADT().get(0).get(0).getBookingCode().get(0);

Bean转JSON

5.x的Hutool中增加了一个自定义注解:@Alias,通过此注解可以给Bean的字段设置别名。

@Data
public class Test {
    private String name;

    @Alias("aliasSex")
    private String sex;

    public static void main(String[] args) {
        Test test = new Test();
        test.setName("handy");
        test.setSex("男");
        // 结果: {"name":"handy","aliasSex":"男"}
        String json = JSONUtil.toJsonStr(test);
    }

}

readXXX

这类方法主要是从JSON文件中读取JSON对象的快捷方法。包括:

  • readJSON

  • readJSONObject

  • readJSONArray

其它方法

除了上面中常用的一些方法,JSONUtil还提供了一些JSON辅助方法:

  • quote 对所有双引号做转义处理(使用双反斜杠做转义)

  • wrap 包装对象,可以将普通任意对象转为JSON对象

  • formatJsonStr 格式化JSON字符串,此方法并不严格检查JSON的格式正确与否

JSON对象-JSONObject

介绍

JSONObject代表一个JSON中的键值对象,这个对象以大括号包围,每个键值对使用,隔开,键与值使用:隔开,一个JSONObject类似于这样:

{
  "key1":"value1",
  "key2":"value2"
}

此处键部分可以省略双引号,值为字符串时不能省略,为数字或布尔值时不加双引号。

使用

创建

JSONObject json1 = JSONUtil.createObj()
  .put("a", "value1")
  .put("b", "value2")
  .put("c", "value3");

JSONUtil.createObj()是快捷新建JSONObject的工具方法,同样我们可以直接new:

JSONObject json1 = new JSONObject();
...

转换

  1. JSON字符串解析

String jsonStr = "{\"b\":\"value2\",\"c\":\"value3\",\"a\":\"value1\"}";
//方法一:使用工具类转换
JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
//方法二:new的方式转换
JSONObject jsonObject2 = new JSONObject(jsonStr);

//JSON对象转字符串(一行)
jsonObject.toString();

// 也可以美化一下,即显示出带缩进的JSON:
jsonObject.toStringPretty();
  1. JavaBean解析

首先我们定义一个Bean

// 注解使用Lombok
@Data
public class UserA {
	private String name;
	private String a;
	private Date date;
	private List<Seq> sqs;
}

解析为JSON:

UserA userA = new UserA();
userA.setName("nameTest");
userA.setDate(new Date());
userA.setSqs(CollectionUtil.newArrayList(new Seq(null), new Seq("seq2")));

// false表示不跳过空值
JSONObject json = JSONUtil.parseObj(userA, false);
Console.log(json.toStringPretty());

结果:

{
    "date": 1585618492295,
    "a": null,
    "sqs": [
        {
            "seq": null
        },
        {
            "seq": "seq2"
        }
    ],
    "name": "nameTest"
}

可以看到,输出的字段顺序和Bean的字段顺序不一致,如果想保持一致,可以:

// 第二个参数表示保持有序
JSONObject json = JSONUtil.parseObj(userA, false, true);

结果:

{
    "name": "nameTest",
    "a": null,
    "date": 1585618648523,
    "sqs": [
        {
            "seq": null
        },
        {
            "seq": "seq2"
        }
    ]
}

默认的,Hutool将日期输出为时间戳,如果需要自定义日期格式,可以调用:

json.setDateFormat("yyyy-MM-dd HH:mm:ss");

得到结果为:

{
    "name": "nameTest",
    "a": null,
    "date": "2020-03-31 09:41:29",
    "sqs": [
        {
            "seq": null
        },
        {
            "seq": "seq2"
        }
    ]
}

JSON数组-JSONArray

介绍

在JSON中,JSONArray代表一个数组,使用中括号包围,每个元素使用逗号隔开。一个JSONArray类似于这样:

["value1","value2","value3"]

使用

创建

//方法1
JSONArray array = JSONUtil.createArray();
//方法2
JSONArray array = new JSONArray();

array.add("value1");
array.add("value2");
array.add("value3");

//转为JSONArray字符串
array.toString();

从Bean列表解析

先定义bean:

@Data
public class KeyBean{
	private String akey;
	private String bkey;
}
KeyBean b1 = new KeyBean();
b1.setAkey("aValue1");
b1.setBkey("bValue1");
KeyBean b2 = new KeyBean();
b2.setAkey("aValue2");
b2.setBkey("bValue2");

ArrayList<KeyBean> list = CollUtil.newArrayList(b1, b2);

// [{"akey":"aValue1","bkey":"bValue1"},{"akey":"aValue2","bkey":"bValue2"}]
JSONArray jsonArray = JSONUtil.parseArray(list);

// aValue1
jsonArray.getJSONObject(0).getStr("akey");

从JSON字符串解析

String jsonStr = "[\"value1\", \"value2\", \"value3\"]";
JSONArray array = JSONUtil.parseArray(jsonStr);

转换为bean的List

先定义一个Bean

@Data
static class User {
	private Integer id;
	private String name;
}
String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]";
JSONArray array = JSONUtil.parseArray(jsonArr);

List<User> userList = JSONUtil.toList(array, User.class);

// 111
userList.get(0).getId();

转换为Dict的List

Dict是Hutool定义的特殊Map,提供了以字符串为key的Map功能,并提供getXXX方法,转换也类似:

String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]";
JSONArray array = JSONUtil.parseArray(jsonArr);

List<Dict> list = JSONUtil.toList(array, Dict.class);

// 111
list.get(0).getInt("id");

转换为数组

String jsonArr = "[{\"id\":111,\"name\":\"test1\"},{\"id\":112,\"name\":\"test2\"}]";
JSONArray array = JSONUtil.parseArray(jsonArr);

User[] list = array.toArray(new User[0]);

JSON路径

如果JSON的层级特别深,那么获取某个值就变得非常麻烦,代码也很臃肿,Hutool提供了getByPath方法可以通过表达式获取JSON中的值。

String jsonStr = "[{\"id\": \"1\",\"name\": \"a\"},{\"id\": \"2\",\"name\": \"b\"}]";
final JSONArray jsonArray = JSONUtil.parseArray(jsonStr);

// b
jsonArray.getByPath("[1].name");

Ciallo~(∠・ω< )⌒☆