学习目标
一、对给定的几种有共同特性的JSON数据抽象出泛型基类及实体类,并使用JSON数据解析库(Jackson、Gson、FastJSON),把对象序列化为JSON字符串,以及把JSON字符串反序列化为类对象。本人在这篇文章中使用的是GSON解析库。
扩展学习:了解Jackson、Gson、FastJSON这三种JSON解析库,分析三者的优缺点。
首先先将GSON包导入到项目中的lib文件夹,我用的是GSON.2.8.5版本,当然也可通过在gradle文件里添加依赖,
implementation 'com.google.code.gson:gson:2.8.5'
一、根据给出的数据格式编写简单实体类,给出实体类的代码以及相关的序列化和反序列化代码。
{
"code": 1,
"data": {
"describe": "example data",
"stringList": [
"zhangsan",
"lisi",
"wangwu"
],
"objArray": [
{
"name": "张三",
"addr": "xxx街道"
},
{
"name": "李四",
"addr": "y市"
}
]
}
}
1.编写一个简易的界面,用LinearLayout布局,自上而下三个控件,EditText编辑文本框,Button按钮,TextView文字显示框
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/inputText"/>
<Button
android:layout_width="100dp"
android:layout_height="40dp"
android:id="@+id/button_1"
android:onClick="button_1_onClick"
android:layout_marginTop="30dp"
android:layout_marginLeft="20dp"
android:text="反序列化"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="输出框"
android:id="@+id/text"
android:textSize="15dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
2.根据JSON数据编写对应的类SimpleJSON,同时SimpleJSON的属性包含一个Data对象,一层一层定义,以此类推,建立Data类,Name类......
//编写JSON格式对应的简单实体类
public class SimpleJSON {
private int code;
private Data data;
@Override
public String toString() {
return "SimpleJSON{" +
"code=" + code +
", data=" + data.toString() +
'}';
}
//默认构造方法
public SimpleJSON(){}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
}
import java.util.ArrayList;
//SimpleJSON中的data对象类
public class Data {
private String describe;
private ArrayList<String> stringList;
private ArrayList<Name> objArray;
@Override
public String toString() {
return "Data{" +
"describe='" + describe + '\'' +
", stringList=" + stringList +
", objArray=" + objArray +
'}';
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
public ArrayList<String> getStringList() {
return stringList;
}
public void setStringList(ArrayList<String> stringList) {
this.stringList = stringList;
}
public ArrayList<Name> getObjArray() {
return objArray;
}
public void setObjArray(ArrayList<Name> objArray) {
this.objArray = objArray;
}
}
//objArray中的Name对象类
public class Name {
private String name;
private String addr;
@Override
public String toString() {
return "Name{" +
"name='" + name + '\'' +
", addr='" + addr + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
3.编写一个利用GSON解析库解析JSON数据的工具类,采用GSON的两种做法
1.利用GSON官方文档中的按层解析法,逐步解析
import com.google.gson.stream.JsonReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Test {
public String set(String str) throws IOException {
//读取字符串转化为输入流再转化为JsonReader
InputStream is = new ByteArrayInputStream(str.getBytes());
InputStreamReader in = new InputStreamReader(is);
JsonReader jsonReader = new JsonReader(in);
SimpleJSON simpleJSON = readSimpleJSON(jsonReader);
return simpleJSON.toString();
}
public Test(){}
//读取简单实体类
private SimpleJSON readSimpleJSON(JsonReader jsonReader) throws IOException {
SimpleJSON simpleJSON = new SimpleJSON();
//读取对象用下面这种方法
jsonReader.beginObject();
//判断指针是否到尾
while(jsonReader.hasNext()){
String str = jsonReader.nextName();
if("code".equals(str)){
simpleJSON.setCode(jsonReader.nextInt());
}
else if("data".equals(str)){
simpleJSON.setData(readData(jsonReader));
}
//跳过这次判断,即特殊情况为空时,不做任何处理,直接返回空值
else jsonReader.skipValue();
}
jsonReader.endObject();
return simpleJSON;
}
//读取SimpleJSON实体类内部的封装数据实体类data
private Data readData(JsonReader jsonReader) throws IOException {
Data data = new Data();
jsonReader.beginObject();
while(jsonReader.hasNext()){
String str = jsonReader.nextName();
if("describe".equals(str)){
data.setDescribe(jsonReader.nextString());
}
else if("stringList".equals(str)){
data.setStringList(readStringList(jsonReader));
}
else if("objArray".equals(str)){
data.setObjArray(readObjArray(jsonReader));
}
else jsonReader.skipValue();
}
jsonReader.endObject();
return data;
}
//读取内部数组类型objArray,读取数组类型用以下方法
private ArrayList<Name> readObjArray(JsonReader jsonReader) throws IOException {
ArrayList<Name> list = new ArrayList<>();
jsonReader.beginArray();
while(jsonReader.hasNext()){
list.add(readName(jsonReader));
}
jsonReader.endArray();
return list;
}
//读取数组中的对象Name
private Name readName(JsonReader jsonReader) throws IOException {
Name name = new Name();
jsonReader.beginObject();
while(jsonReader.hasNext()){
String str = jsonReader.nextName();
if("name".equals(str)){
name.setName(jsonReader.nextString());
}
else if("addr".equals(str)){
name.setAddr(jsonReader.nextString());
}
else jsonReader.skipValue();
}
jsonReader.endObject();
return name;
}
//读取stringArray类型数组
private ArrayList<String> readStringList(JsonReader jsonReader) throws IOException {
ArrayList<String> list = new ArrayList<>();
jsonReader.beginArray();
while(jsonReader.hasNext()){
list.add(jsonReader.nextString());
}
jsonReader.endArray();
return list;
}
}
2.利用GSON自带的解析方法,快速解析
//将JSON数据反序列化为Java类对象简单方法,此方法解析时,一定要将此部分放入try-catch语句中,不然会因为数据格式不正确而导致闪退
Gson gson = new Gson();
SimpleJSON obj= gson.fromJson(in,SimpleJSON.class);
3.序列化操作,为了方便演示,即采用上述第 3.1 步反序列化的出来的对象
//将对象序列化为JSON数据
Gson gson = new Gson();
String json = gson.toJson(simpleJSON);
System.out.println(json);
4.在MainActivity中进行控件初始化,并测试JSON数据是否解析成功
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
//声明所有控件
private TextView textView;
private Button button_1;
private EditText inputText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化
init();
}
//初始化绑定控件
public void init(){
textView = findViewById(R.id.text);
button_1 = findViewById(R.id.button_1);
inputText = findViewById(R.id.inputText);
}
//绑定简单实体类点击事件
public void button_1_onClick(View view) {
String str = inputText.getText().toString();
Test test = new Test();
try {
textView.setText(test.set(str));
} catch (IOException e) {
textView.setText("JSON格式不正确");
}
}
}
5.执行结果
二、带泛型的实体类,事实上需要写4个实体类,一个最外层定义泛型的类如BaseData,以及3个具体的数据实体类Data1 Data2 Data3
//这是三个JSON数据,不是一个,输入时分开输入
{
"errorCode": 0,
"obj": {
"user": "admin",
"attr": {
"prefix": "start-",
"suffix": ".jpg"
}
}
}
{
"errorCode": 0,
"obj": {
"name": "cat",
"style": {
"width": 1920,
"height": 1080
}
}
}
{
"errorCode": 0,
"obj": "hello"
}
1.添加一个按钮控件,同时将按钮控件都放在一个LinearLayout内部实现水平布局
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="30dp"
android:onClick="button_2_onClick"
android:text="泛型反序列化" />
2.根据对应实体类,编写相应的泛型内和实体类,即GenericsJSON基类,和Obj1,Obj2,Obj3数据实体类,因为Obj3的数据类型为String,故不用实现Obj3数据类
//基类
public class GenericsJSON<T> {
private int errorCode;
T obj;
@Override
public String toString() {
return "GenericsJSON{" +
"errorCode=" + errorCode +
", obj=" + obj.toString() +
'}';
}
GenericsJSON(){}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
//Obj1数据类
public class Obj1 {
private String user;
private Attr attr;
@Override
public String toString() {
return "Obj1{" +
"user='" + user + '\'' +
", attr=" + attr +
'}';
}
Obj1(){}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public Attr getAttr() {
return attr;
}
public void setAttr(Attr attr) {
this.attr = attr;
}
public class Attr{
private String prefix;
private String suffix;
Attr(){}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
}
//Obj2数据类
public class Obj2 {
private String name;
private Style style;
Obj2(){}
@Override
public String toString() {
return "Obj2{" +
"name='" + name + '\'' +
", style=" + style +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Style getStyle() {
return style;
}
public void setStyle(Style style) {
this.style = style;
}
public class Style{
private int width;
private int hight;
Style(){}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHight() {
return hight;
}
public void setHight(int hight) {
this.hight = hight;
}
}
}
3.编写工具类Test1
import com.google.gson.Gson;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test1{
public String set1(String str) {
//读取字符串转化为输入流再转化为JsonReader
InputStream is = new ByteArrayInputStream(str.getBytes());
InputStreamReader in = new InputStreamReader(is);
try{
//将JSON数据反序列化为Java类对象简单方法
Gson gson = new Gson();
GenericsJSON<Obj1> obj1 = gson.fromJson(in, GenericsJSON.class);
//将对象序列化为JSON数据
Gson gson1 = new Gson();
String json = gson1.toJson(obj1);
System.out.println(json);
return obj1.toString();
}catch(Exception e){
return "JSON数据格式不正确";
}
}
public String set2(String str) {
//读取字符串转化为输入流再转化为JsonReader
InputStream is = new ByteArrayInputStream(str.getBytes());
InputStreamReader in = new InputStreamReader(is);
try{
//将JSON数据反序列化为Java类对象简单方法
Gson gson = new Gson();
GenericsJSON<Obj2> obj2 = gson.fromJson(in, GenericsJSON.class);
//将对象序列化为JSON数据
Gson gson1 = new Gson();
String json = gson1.toJson(obj2);
System.out.println(json);
return obj2.toString();
}catch(Exception e){
return "JSON数据格式不正确";
}
}
public String set3(String str) {
//读取字符串转化为输入流再转化为JsonReader
InputStream is = new ByteArrayInputStream(str.getBytes());
InputStreamReader in = new InputStreamReader(is);
try{
//将JSON数据反序列化为Java类对象简单方法
Gson gson = new Gson();
GenericsJSON<String> obj3 = gson.fromJson(in, GenericsJSON.class);
//将对象序列化为JSON数据
Gson gson1 = new Gson();
String json = gson1.toJson(obj3);
System.out.println(json);
return obj3.toString();
}catch(Exception e){
return "JSON数据格式不正确";
}
}
}
4.实现按钮控件事件,这里为了省去麻烦,同一个按钮分别测试三次不同类型的JSON数据
public void button_2_onClick(View view) {
String str = inputText.getText().toString();
//第一个JSON格式
Test1 test1 = new Test1();
textView.setText(test1.set1(str));
//
// //第二个JSON格式
// Test1 test2 = new Test1();
// textView.setText(test2.set2(str));
//
// //第三个JSON格式
// Test1 test3 = new Test1();
// textView.setText(test3.set3(str));
}
5.执行结果
三、自定义反序列化,要求使用接口或基类定义datas列表里的数据类型,然后自定义反序列化,根据typeCode反序列化为不同的实现类
{
"datas": [
{
"typeCode": 1,
"typeName": "type1",
"attr": {
"prefix": "fff",
"suffix": "xsss"
},
"msg":"hello"
},
{
"typeCode": 2,
"typeName": "type2",
"style": {
"size": 12,
"color": "#FF5A207E"
},
"text": "thanks"
}
]
}
1.添加一个按钮控件
<Button
android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginLeft="5dp"
android:layout_marginTop="30dp"
android:onClick="button_3_onClick"
android:text="自定义反序列化" />
2.根据JSON格式实现对象类,这个地方的类定义和相互之间的关系很重要,首先是datas类型的数组类,里面包括着一个DataType父类,只有一个属性typeCode,接着实现两个子类Data1,Data2继承DataType
import java.util.ArrayList;
import java.util.List;
//JSON中的datas数组类
public class Datas {
//定义一个DataType类型数组
private List<DataType> datas;
@Override
public String toString() {
return "Datas{" +
"datas=" + datas +
'}';
}
public Datas(){
datas = new ArrayList<>();
}
public List<DataType> getList() {
return datas;
}
public void setList(List<DataType> datas) {
this.datas = datas;
}
}
//父类DataType,只有一个属性typeCode,其他的属性在子类里声明
public class DataType {
private int typeCode;
@Override
public String toString() {
return "DataType{" +
"typeCode=" + typeCode +
'}';
}
public int getTypeCode() {
return typeCode;
}
public void setTypeCode(int typeCode) {
this.typeCode = typeCode;
}
DataType(){}
}
//typeCode为1的子类
public class Data1 extends DataType{
private String typeName;
private Attr attr;
private String msg;
@Override
public String toString() {
return "Data1{" +
"typeName='" + typeName + '\'' +
", attr=" + attr +
", msg='" + msg + '\'' +
'}';
}
Data1(){}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public Attr getAttr() {
return attr;
}
public void setAttr(Attr attr) {
this.attr = attr;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
//内部的Attr对象类
public class Attr{
private String prefix;
private String suffix;
@Override
public String toString() {
return "Attr{" +
"prefix='" + prefix + '\'' +
", suffix='" + suffix + '\'' +
'}';
}
Attr(){}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
}
//typeCode为2的子类
public class Data2 extends DataType{
private String typeName;
private Style style;
private String text;
Data2(){}
@Override
public String toString() {
return "Data2{" +
"typeName='" + typeName + '\'' +
", style=" + style +
", text='" + text + '\'' +
'}';
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public Style getStyle() {
return style;
}
public void setStyle(Style style) {
this.style = style;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
//内部style类对象
public class Style{
private int size;
private String color;
@Override
public String toString() {
return "Style{" +
"size=" + size +
", color='" + color + '\'' +
'}';
}
Style(){}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
}
3.根据需要,实现自定义反序列化方法DataDeserializer类
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test2 {
public String set(String str){
//读取字符串转化为输入流再转化为JsonReader
InputStream is = new ByteArrayInputStream(str.getBytes());
InputStreamReader in = new InputStreamReader(is);
try{
//注册自定义反序列化方法
GsonBuilder gsonBuilder = new GsonBuilder();
JsonDeserializer<DataType> deserializer = new DataDeserializer();
gsonBuilder.registerTypeAdapter(DataType.class,deserializer);
Gson gson = gsonBuilder.create();
//实现自定义反序列化
Datas list = gson.fromJson(in, Datas.class);
//将对象序列化为JSON数据
Gson gson1 = new Gson();
String json = gson1.toJson(list);
System.out.println(json);
return list.toString();
}catch(Exception e){
return "JSON数据格式不正确";
}
}
}
4.编写JSON解析操作类Test2
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test2 {
public String set(String str){
//读取字符串转化为输入流再转化为JsonReader
InputStream is = new ByteArrayInputStream(str.getBytes());
InputStreamReader in = new InputStreamReader(is);
try{
//注册自定义反序列化方法
Gson gson = new GsonBuilder().serializeNulls().create();
//实现自定义反序列化
Datas list = gson.fromJson(in, Datas.class);
//将对象序列化为JSON数据
Gson gson1 = new Gson();
String json = gson1.toJson(list);
System.out.println(json);
return list.toString();
}catch(Exception e){
return "JSON数据格式不正确";
}
}
}
5.编写按钮事件
public void button_3_onClick(View view) {
String str = inputText.getText().toString();
Test2 test = new Test2();
textView.setText(test.set(str));
}
6.执行结果
扩展学习:了解Jackson、Gson、FastJSON这三种JSON解析库,分析三者的优缺点。
因为我还未使用过Jackson和FastJSON解析库,所以我上网查阅了资料,大部分数据都显示,若是解析少量的JSON数据,GSON的效率相对而言效果较好,FastJSON也不错,但如果是十分大量的数据,Jackson解析库就显现出了其优势。FastJSON设计的初衷就是为了解析快,所以重点都放在了“快”,但“功能性”相比Jaskson而言就自愧不如了,所以说,如果作为SpringBoot技术栈开发的话, 用默认的Jackson是再好不过了,现在的项目开发也大多数是使用Jackson。
作者有道云原文链接:
https://note.youdao.com/s/JLzf9n2Ihttps://note.youdao.com/s/JLzf9n2I