JSON
- 定义:JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式
- 作用:数据标记,存储,传输
- 特点:
- 读写速度快
- 解析简单
- 轻量级
- 独立于语言,平台
- 具有自我描叙性
- JSON解析:
- 语法:JSON建构于两种结构:
- “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
- 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
JSON具有以下这些形式:
对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
{
"name": "英语",
"score": 78.3
}
组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
"courses": [
{
"name": "英语",
"score": 78.3
}
]
(value)可以是双引号括起来的字符串(string)、数值(number)、true
、false
、 null
、对象(object)或者数组(array)。这些结构可以嵌套。
{
"url": "https://qqe2.com",
"name": "欢迎使用JSON在线解析编辑器",
"array": {
"JSON校验": "http://jsonlint.qqe2.com/",
"Cron生成": "http://cron.qqe2.com/",
"JS加密解密": "http://edit.qqe2.com/"
},
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
}
}
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。字符串(string)与C或者Java的字符串非常相似。
{
"name": "Zero",
}
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
{
"age": 28,
}
JSON解析方式
- Android Studio自带org.json解析
-1 解析原理:基于文档驱动,需要把全部文件读入到内存中,然后遍历所有数据,根据需要检索想要的数据
-2 具体使用:
//生成JSON
private void createJson(Context context) throws Exception {
File file = new File(getFilesDir(), "orgjson.json");//获取到应用在内部的私有文件夹下对应的orgjson.json文件
JSONObject student = new JSONObject();//实例化一个JSONObject对象
student.put("name", "OrgJson");//对其添加一个数据
student.put("sax", "男");
student.put("age", 23);
JSONObject course1 = new JSONObject();
course1.put("name", "语文");
course1.put("score", 98.2f);
JSONObject course2 = new JSONObject();
course2.put("name", "数学");
course2.put("score", 93.2f);
JSONArray coures = new JSONArray();//实例化一个JSON数组
coures.put(0, course1);//将course1添加到JSONArray,下标为0
coures.put(1, course2);
//然后将JSONArray添加到名为student的JSONObject
student.put("courses", coures);
FileOutputStream fos = new FileOutputStream(file);
fos.write(student.toString().getBytes());
fos.close();
Log.i(TAG, "createJson: " + student.toString());
Toast.makeText(context, "创建成功", Toast.LENGTH_LONG).show();
}
//解析JSON
private void parseJson(Context context) throws Exception {
File file = new File(getFilesDir(), "orgjson.json");
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String line;
StringBuffer sb = new StringBuffer();
while (null != (line = br.readLine())) {
sb.append(line);
}
fis.close();
isr.close();
br.close();
Student student = new Student();
//利用JSONObject进行解析
JSONObject stuJsonObject = new JSONObject(sb.toString());
//为什么不用getString?
//optString会在得不到你想要的值时候返回空字符串"",而getString会抛出异常
String name = stuJsonObject.optString("name", "");
student.setName(name);
student.setSax(stuJsonObject.optString("sax", "男"));
student.setAge(stuJsonObject.optInt("age", 18));
//获取数组数据
JSONArray couresJson = stuJsonObject.optJSONArray("courses");
for (int i = 0; i < couresJson.length(); i++) {
JSONObject courseJsonObject = couresJson.getJSONObject(i);
Course course = new Course();
course.setName(courseJsonObject.optString("name", ""));
course.setScore((float) courseJsonObject.optDouble("score", 0));
student.addCourse(course);
}
Log.i(TAG, "parseJson: " + student);
Toast.makeText(context, "解析成功", Toast.LENGTH_LONG).show();
}
Gson 解析
- 解析原理:基于事件驱动
- 解析流程:根据所需取的数据 建立1个对应于JSON数据的JavaBean类,即可通过简单操作解析出所需数据
- Gson 不要求JavaBean类里面的属性一定全部和JSON数据里的所有key相同,可以按需取数据
- 具体实现:
- 创建一个与JSON数据对应的JavaBean类(用作存储需要解析的数据)
- JSON的大括号对应一个对象
-1 对象里面有key,value
-2 JavaBean的类属性名 = key - JSON的方括号对应一个数组
-1 JavaBean里面对应的也是数组
-2 对象里 可以有值/对象
-3 若对象里面只有值,没有key,则说明是纯数组,对应JavaBean里的数组类型
-4 若对象里面有值和key,则说明是对象数组,对应JavaBean里的内部类 - 对象嵌套
-1 建立内部类 该内部类对象的名字 = 父对象的key ,类似对象数组
- JSON的大括号对应一个对象
{
"key": "value",
"simpleArray": [1,2,3],
"arrays": [
[{
"arrInnerClsKey": "arrInnerClsValue",
"arrInnerClsKeyNub": 1
}]
],
"innerclass": {
"name": "zero",
"age": 25,
"sax": "男"
}
}
- 转化成JavaBean
public class GsonBean {
public String key;
public InnerclassBean innerclass;
public List simpleArray;
public List> arrays;
public static class InnerclassBean {
public String name;
public int age;
public String sax;
}
public static class ArraysBean {
public String arrInnerClsKey;
public int arrInnerClsKeyNub;
}
}
- 使用例子
public static void main(String... args) throws Exception {
Student student = new Student();
student.setName("Zero");
student.setSax("男");
student.setAge(28);
student.addCourse(new Course("英语", 78.3f));
Gson gson = new Gson();
//1. 生成json文件
File file = new File(CurPath + "/gsonjsontest.json");
OutputStream oot = new FileOutputStream(file);
JsonWriter jw = new JsonWriter(new OutputStreamWriter(oot, "utf-8"));
gson.toJson(student, new TypeToken() {}.getType(), jw);
jw.flush();
jw.close();
//反序列化
Student student1 = gson.fromJson(new JsonReader(new InputStreamReader(new
FileInputStream(file))) , new TypeToken() {}.getType());
System.out.println(student1);
}
Jackson解析
- 解析原理:基于事件驱动
- 解析过程:
- 类似 GSON,先创建1个对应于JSON数据的JavaBean类,再通过简单操作即可解析
- 与 Gson解析不同的是:GSON可按需解析,即创建的JavaBean类不一定完全涵盖所要解析的JSON数据,按需创建属性;但Jackson解析对应的JavaBean必须把Json数据里面的所有key都有所对应,即必须把JSON内的数据所有解析出来,无法按需解析
Gson原理解析
在这个序列化和反序列化的过程中,充当的了一个解析器的角色JsonElement
该类是一个抽象类,代表着json串的某一个元素。这个元素可以是一个Json(JsonObject)、可以是一个数组(JsonArray)、可以是一个Java的基本类型(JsonPrimitive)、当然也可以为null(JsonNull);JsonObject,JsonArray,JsonPrimitive,JsonNull都是JsonElement这个抽象类的子类。JsonElement提供了一系列的方法来判断当前的JsonElement
各个JsonElement的关系可以用如下图表示:
JsonObject对象可以看成 name/values的集合,而这写values就是一个个JsonElement,他们的结构可以用如下图表示:
JsonDeserializer的工作原理
TypeAdapter的工作原理
Gson的整体解析原理
Gson的反射解析机制
Gson解析常见的错误
- Expected BEGIN_ARRAY but was STRING at line 1 column 27
这种错误一般都是原来是一个字段需要是数组类型,但是事实上给的是"",导致的
-解决办法
- 让返回null即可解决问题
- 用Gson自带的解决方案
static class GsonError1Deserializer implements JsonDeserializer {
@Override
public GsonError1 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final JsonElement jsonTitle = jsonObject.get("name");
final String name = jsonTitle.getAsString();
JsonElement jsonAuthors = jsonObject.get("authors");
GsonError1 gsonError1 = new GsonError1();
if (jsonAuthors.isJsonArray()) {//如果数组类型,此种情况是我们需要的
//关于context在文章最后有简单说明
GsonError1.AuthorsBean[] authors = context.deserialize(jsonAuthors, GsonError1.AuthorsBean[].class);
gsonError1.setAuthors(Arrays.asList(authors));
} else {//此种情况为无效情况
gsonError1.setAuthors(null);
}
gsonError1.setName(name);
return gsonError1;
}
}
static class AuthorDeserializer implements JsonDeserializer {
@Override
public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final GsonError1.AuthorsBean author = new GsonError1.AuthorsBean();
author.setId(jsonObject.get("id").getAsString());
author.setName(jsonObject.get("name").getAsString());
return author;
}
}
public static void main(String... args) {
// test1();
// test2();
test3();
}
public static void test1() {
String json = "{\n" +
" \"name\": \"java\",\n" +
" \"authors\": [\n" +
" {\n" +
" \"id\": \"1'\",\n" +
" \"name\": \"Joshua Bloch'\"\n" +
" },\n" +
" {\n" +
" \"id\": \"2'\",\n" +
" \"name\": \"Tom\"\n" +
" }\n" +
" ]\n" +
"}";
Gson gson = new Gson();
GsonError1 gsonError1 = gson.fromJson(json, GsonError1.class);
System.out.println(gsonError1);
}
public static void test2() {
//TODO:
String json = "{\n" +
" \"name\": \"java\",\n" +
" \"authors\": \"\"\n" +
"}";
Gson gson = new Gson();
GsonError1 gsonError1 = gson.fromJson(json, GsonError1.class);
System.out.println(gsonError1);
}
public static void test3() {
String json = "{\n" +
" \"name\": \"java\",\n" +
" \"authors\": \"\"\n" +
"}";
GsonBuilder gsonBuilder = new GsonBuilder();
//注册TypeAdapter
gsonBuilder.registerTypeAdapter(GsonError1.class, new GsonError1Deserializer());
gsonBuilder.registerTypeAdapter(GsonError1.AuthorsBean.class, new AuthorDeserializer());
Gson gson = gsonBuilder.create();
GsonError1 gsonError1 = gson.fromJson(json, GsonError1.class);
System.out.println(gsonError1);
}