JSON(JavaScript Object Notation, JavaScript 对象标记语言) 是一种轻量级的数据交换格式。在 JS 语言中,一切都是对象。因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。
JSON 与 JS 对象的关系:JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。如:
//这是一个对象,注意键名也是可以使用引号包裹的
var obj = {a: 'Hello', b: 'World'};
//这是一个 JSON 字符串,本质是一个字符串
var json = '{"a": "Hello", "b": "World"}';
JSON 和 JS 对象互转,如:
//从对象转换为 JSON 字符串
var json = JSON.stringify({a: 'Hello', b: 'World'});
//从 JSON 转换为对象
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
Json数据格式应用在很多场景中,笔者在移动应用开发的过程中深有体会。在做安卓项目的时候,服务器端和客户端之间的数据使用了json数据格式作为传输数据的媒介,在客户端将数据转化为json格式通过socket传送到服务器端,在服务器端将json格式的数据解析为对象,再进行数据持久化操作。本文主要介绍两种开源的Json库——JSON和GSON,JSON是Android SDK官方的库,Gson是google开源的库,基本能够满足一般开发过程中的需求。
1. Java中的JSON
1.1 JSON的使用
导入jar包(json.jar)后,我们可以new一个JSONObject对象操作json数据,json支持String、bool、number和数组类型,以下代码是使用put方法往JSON对象中放入数据,最后我们可以通过toString()方法将JSON对象中的数据打印出来。该种方法构建的JSON对象会自动隐藏value为null的整条数据。
JSONObject json = new JSONObject();
Object object = null;
json.put("name", "lucian");
json.put("age", 20);
json.put("isBoy", true);
json.put("birthday", "1996-8-14");
json.put("hobbits", new String[]{"swimming", "bike"});
json.put("content", object);
System.out.println(json.toString());
1.2 使用Map构建JSON
JSONObject的构造方法中支持传入Map类型参数。由于json中的数据是Key-Value方式存储,而Map的数据格式也Key-Value,所以我们可以通过创建一个Map对象,将数据存入map中,再将map传参进json对象中,放入数据的方式与之前的方法类似。但需要注意的是,Map类是接口,所以不能直接new Map类,需要new Map类的一个具体实现类,下面代码中使用了HashMap作为Map对象的具体实现。
Map map = new HashMap<>();
JSONObject json = new JSONObject(map);
Object object = null;
map.put("name", "lucian");
map.put("age", 20);
map.put("isBoy", true);
map.put("birthday", "1996-8-14");
map.put("hobbits", new String[]{"swimming", "bike"});
map.put("content", object);
System.out.println(json.toString());
1.3 通过javaBean构建JSON对象
在具体项目的开发中,json应用较多的场景是对javaBean进行转化,而不是一个个单独的数据,所以相应的,JSONObject类构造器支持传入对象参数。我们新建了一个People类如下:
public class People {
private String name;
private int age;
private boolean isBoy;
private String birthday;
private String[] hobbits;
private Object content;
public People(String name, int age, boolean isBoy, String birthday, String[] hobbits, Object content) {
super();
this.name = name;
this.age = age;
this.isBoy = isBoy;
this.birthday = birthday;
this.hobbits = hobbits;
this.content = content;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isBoy() {
return isBoy;
}
public void setBoy(boolean isBoy) {
this.isBoy = isBoy;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String[] getHobbits() {
return hobbits;
}
public void setHobbits(String[] hobbits) {
this.hobbits = hobbits;
}
public Object getContent() {
return content;
}
public void setContent(Object content) {
this.content = content;
}
}
通过构造器模拟创建一个包含数据的People对象,可以直接将该javaBean转化为json对象。
People people = new People("lucian", 20, true, "1996-08-14", new String[]{"swimming", "bike"}, null);
JSONObject jsonObject = new JSONObject(people);
System.out.println(jsonObject.toString());
1.4 从文件读取json
首先,我们创建一个test.json文本文件,其中存储一些json格式数据,如下:
{
"hobbits": [
"swimming",
"bike"
],
"name": "lucian",
"age": 20,
"isBoy": true,
"birthday": "1996-8-14",
"content": null
}
首先我们需要获取到test.json的路径,然后读取到整个文件的内容,存储到content变量中,注意,这儿我们使用了FileUtils工具包,需要导入commons-io.jar,用于简化整个文件读取的操作。然后将content变量以构造方法传参的形式创建出json对象。
File file = new File(JSONGet.class.getResource("test.json").getPath());
String content = FileUtils.readFileToString(file);
JSONObject jsonObject = new JSONObject(content);
此时,jsonObjct对象中便存储了test.json的数据。接下来,我们需要了解如何获取该对象中的数据。对于普通的json数据类型,只需要使用getString、getInt等方法便可以获得。代码如下:
System.out.println("name:" + jsonObject.getString("name"));
System.out.println("age:" + jsonObject.getInt("age"));
输出:
name:lucian
age:20
而对于数组类型的数据较为特殊,需要声明一个JSONArray对象,通过getJSONArray方法将json数组赋给JSONArray对象引用,通过遍历该对象输出数据。代码如下:
JSONArray hobbits = jsonObject.getJSONArray("hobbits");
for (int i = 0; i < hobbits.length(); i++) {
System.out.println("hobits-" + (i+1) + hobbits.get(i));
}
输出如下:
hobits-1swimming
hobits-2bike
2. Gson的使用
2.1 Gson简介
Gson是google解析Json的一个开源框架,它与JsonObject相比,功能更加强大,性能上更加出色,使用上也更加便捷与简单。需要导入gson相关jar包gson.jar。
2.2 Gson生成Json数据
首先最常规的一种生成方式便是new一个Gson对象,再通过含参构造器实例化一个People对象,通过gson.toJson方法将实例化的people对象传入Gson中,生成Json数据。
People people = new People("lucian", 20, true, "1996-08-14", new String[]{"swimming", "bike"}, null);
Gson json = new Gson();
System.out.println(json.toJson(people));
并且Gson可以通过gsonBuilder创建一个Gson对象,并对该对象设置格式化输出。
People people = new People("lucian", 20, true, "1996-08-14", new String[]{"swimming", "bike"}, null);
GsonBuilder gsonBuilder = new GsonBuilder();
//格式化输出
gsonBuilder.setPrettyPrinting();
Gson json = gsonBuilder.create();
System.out.println(json.toJson(people));
在实际应用当中,我们可能会有一些个性化需求,例如name属性的属性名需要是大写的,在gson中,我们便可以通过设置FieldNamingStrategy对json对象中属性的名称进行更改,示例如下:
People people = new People("lucian", 20, true, "1996-08-14", new String[]{"swimming", "bike"}, null);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingStrategy(new FieldNamingStrategy() {
@Override
public String translateName(Field arg0) {
if(arg0.getName().equals("name")) {
return "NAME";
}
return arg0.getName();
}
});
Gson json = gsonBuilder.create();
System.out.println(json.toJson(people));
上述示例中,将属性名为name的属性重新更改了其属性名为NAME。
需要更改属性名还有另外一种更加方便快捷的方法,便是在People类的相应属性上增加注释,将People类中的相应代码修改为如下代码,效果与上述示例相同。
@SerializedName(value = "NAME")
private String name;
json中并没有给我们提供注释这一功能,而有时候我们又需要对json的数据进行一个解释说明,用一位老师的话来说,就是使用曲线救国的方法,在json中再增加一个变量description,在其中存入注解。但是很多时候我们并不希望这部分数据直接的显示出来。我们可以通过在相应的属性上加上transient关键字,打印数据时便不会输出这一属性。如下:
//不显示
private transient boolean isBoy;
2.3 Gson解析
我们仍然使用之前的test.json文件作为测试数据,解析方法和JSONObject基本相同。获取数组数据时更加方便,可以直接get而不需要新建jsonarray对象。
File file = new File(JSONGet.class.getResource("test.json").getPath());
String content = FileUtils.readFileToString(file);
Gson gson = new GsonBuilder().create();
People people = gson.fromJson(content, People.class);
System.out.println(people.getName());
System.out.println(people.getHobbits()[0]);
2.4 Gson解析——带日期转换
在JSONObject中,日期只能以String类型的方式进行输出,而Date类型的日期格式比较容易为我们所用。所以Gson支持Date类型数据的转化。首先我们需要对People类稍加修改,修改为PeopleWithBirthday(构造方法和get、set方法在此省略)。
public class PeopleWithBirthday {
private String name;
private int age;
private transient boolean isBoy;
private Date birthday;
private String[] hobbits;
private Object content;
}
注意属性birthday为Date类型,通过gson构造器设置了json文件中的日期格式,以下代码是对json文件中的日期进行解析并格式化输出。
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
PeopleWithBirthday people = gson.fromJson(content, PeopleWithBirthday.class);
SimpleDateFormat ff = new SimpleDateFormat("yyyy-MM-dd");
String tmp = ff.format(people.getBirthday());
System.out.println(tmp);
输出结果为:1996-08-14
关于JSON库的总结
功能:映射Java Object和json格式数据
特点:
1.通过Annotation注解来声明;
2.支持自定义属性名字;
3.支持包含或排除属性;
4.支持自定义接口完成解析/生成过程。