前言

在日常开发中,我们经常会用到json转对象,或者对象转json的情况,一般用到的就是阿里的Fastjson和谷歌的Gson。

本篇要说的是Gson中如何将json数据转换为我们想要的数据类型。

1.json直接转对象

我们一般的操作姿势:

直接复制后台下发的json,然后在Android Studio使用Gson插件快捷生成实体类:

但是呢,有时候

这块是一个模版json,我们在对数据做处理的时候,希望让data给调用者自己去处理。通过传入一个Class类型,来自动把我们data里面的字符串解析成对应的Class对象。

2.泛型化data数据体

public class ApiResultBean<T> {

    /**
     * msg : 获取成功!
     * code : 200
     * data : {}
     */

    private String msg;
    private int code;
    private T data;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
    
}

这样,我们可以把json中,我们需要处理的对象解析为 T类型。

然后在解析服务器返回的json时,我们可以直接通过Gson进行解析:

ApiResultBean responseState = new Gson().fromJson(json, type);

我们看到,在进行解析时,需要传入一个类型,例如:我们的T类型是一个Movie电影列表信息,则可以这样写:

new TypeToken<ApiResultBean<List<MovieBean>>>(){}.getType();

这里的T = List<MovieBean>,这样我们的数据就能正常处理成功了。

如果是一个字符串类型则是T = String

new TypeToken<ApiResultBean<String>>(){}.getType();

但是,使用这种方式的前提是,我们在调用后台API的时候,明确知道,返回的T类型,而且类型是不变的。

例如,后台在做后台推送时,我们不知道后台推送的json数据返回的data数据体是哪种T类型,这个时候,这种方式就无法使用了。

3.Gson类型适配器

我们知道gson是可以自定义json类型解析的,实现方法如下:

public class ApiGsonBuilder {

    private static final GsonBuilder INSTANCE = new GsonBuilder();

    static {
        INSTANCE.disableHtmlEscaping();
        INSTANCE.registerTypeAdapter(MqttBaseMsgBean.class, new MqttMsgAdapter());

    }

    public static Gson create() {
        return INSTANCE.create();
    }
}

第一步:禁用Html转义;

第二步:注册类型adapter,传入我们的json实体类,和解析规则;

第三步:使用自定义的gson对json数据进行解析

下面看下我们的type adapter,以 MqttBaseMsgBean 为例。

MqttBaseMsgBean 主要是根据下发的不同的cmd字符串,来判断需要传入的T类型:

public class MqttBaseMsgBean implements Serializable {

    /**
     * id :
     * ts : 323123213213
     * nonce : xxx
     * sign : xxx
     * cmd : reboot
     * data : {"code":"200","msg":"success"}
     */

    private String id;
    private String ts;
    private String nonce;
    private String sign;
    private String cmd;
    private String data;

    public MqttBaseMsgBean() {

    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTTs() {
        return ts;
    }

    public void setTTs(String ts) {
        this.ts = ts;
    }

    public String getNonce() {
        return nonce;
    }

    public void setNonce(String nonce) {
        this.nonce = nonce;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getCmd() {
        return cmd;
    }

    public void setCmd(String cmd) {
        this.cmd = cmd;
    }

    public String getData() {
        if (data == null) {
            return "{}";
        }
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

}

我们看到data : {"code":"200","msg":"success"},是一个object对象,但是我们把它转换成了String类型,这个时候,我们就可以拿到这个String data,然后在对这个字符串进行解析了,只是比上面传入T类型的方式多了一步类型转换。

那么,我们的MqttMsgAdapter.java,是怎么解析的呢?

public class MqttMsgAdapter implements JsonDeserializer<MqttBaseMsgBean> {

    public MqttBaseMsgBean deserialize(JsonElement json, Type type,
                                 JsonDeserializationContext context)
            throws JsonParseException {
        MqttBaseMsgBean result = new MqttBaseMsgBean();
        JsonObject jsonObject = json.getAsJsonObject();
        JsonElement ret;

        ret = jsonObject.get("id");
        if (ret != null && !ret.isJsonNull()) {
            result.setId(GsonHelper.getAsString(ret));
        }
        ret = jsonObject.get("ts");
        if (ret != null && !ret.isJsonNull()) {
            result.setTTs(GsonHelper.getAsString(ret));
        }
        ret = jsonObject.get("nonce");
        if (ret != null && !ret.isJsonNull()) {
            result.setNonce(GsonHelper.getAsString(ret));
        }
        ret = jsonObject.get("sign");
        if (ret != null && !ret.isJsonNull()) {
            result.setSign(GsonHelper.getAsString(ret));
        }
        ret = jsonObject.get("cmd");
        if (ret != null && !ret.isJsonNull()) {
            result.setCmd(GsonHelper.getAsString(ret));
        }
        ret = jsonObject.get("data");
        if (ret != null && !ret.isJsonNull()) {
            result.setData(ret.toString());
        }

        return result;
    }
}

看到这里,我们一下就清楚了,我们把所有的字段都解析成了JsonElement,然后根据需求,将jsonElement转换成我们需要的类型即可,如:

ret = jsonObject.get("data");
if (ret != null && !ret.isJsonNull()) {
    result.setData(ret.toString());
}

这样,我们就将data这个object类型转换成了String类型,这样第一次Gson解析就完成了。

当我们拿到cmd命令后,根据不同的cmd,就可以对String data 进行不同的转换了:

MqttBaseMsgBean bodyBean = ApiGsonBuilder.create().fromJson(json, MqttBaseMsgBean.class);
if (bodyBean != null && !TextUtils.isEmpty(bodyBean.getCmd())) {
    if (bodyBean.getCmd().equalsIgnoreCase("reboot")) {
        ShellUtil.execShellReboot();
    } else if (bodyBean.getCmd().equalsIgnoreCase("powerOff")) {
        ShellUtil.execShellShutDown();
    } else if (bodyBean.getCmd().equalsIgnoreCase("uploadLog")) {
        MqttLogBean logBean = ApiGsonBuilder.create().fromJson(bodyBean.getData(),   MqttLogBean.class);
        if (logBean != null) {
            uploadLog(context, bodyBean.getId(), logBean);
        }
    }
}

上面的代码中,我们将json转换成了MqttBaseMsgBean对象,然后判断cmd命令是reboot,还是powerOff,还是updataLog?三种类型的命令,来判断我们需要把data字符串,是解析成MqttLogBean,还是直接执行关机或重启动作。

这样就完成了整个json数据的解析。

 

当然,你也可以使用FastJson来解析json数据,各有优势吧。

 

GitHub 加速计划 / js / json
52
5
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:9 天前 )
697c7e55 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.16 to 3.28.17. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/28deaeda66b76a05916b6923827895f2b14ab387...60168efe1c415ce0f5521ea06d5c2062adbeed1b) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 3.28.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 3 天前
9110918c * :pencil2: fix typos Signed-off-by: Niels Lohmann <[email protected]> * :pencil2: address review comments Signed-off-by: Niels Lohmann <[email protected]> * :pencil2: address review comments Signed-off-by: Niels Lohmann <[email protected]> --------- Signed-off-by: Niels Lohmann <[email protected]> 3 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐