Android之JSON与泛型

本文详细介绍了如何使用Gson库在Java中解析JSON数据,包括创建对应的实体类,进行序列化和反序列化操作。此外,还展示了如何处理带泛型的实体类以及自定义反序列化方法,以应对不同类型的数据。最后,对比了Gson、Jackson和FastJSON三种解析库的优缺点。
摘要由CSDN通过智能技术生成

学习目标

一、对给定的几种有共同特性的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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值