使用GSON将JSON转换为嵌套对象(通用对象)

6
我想使用Gson创建一个解析JSON的解析器。
第一个IParser.java。
public interface IParser<T> {
    public T parse(String json);
}

第二个Parser.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class Parser<T> implements IParser<T> {

    @Override
    public T parse(String json) {
        GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.enableComplexMapKeySerialization().create();
        MyJson<T> jsonParsed = gson.fromJson(json, new TypeToken<MyJson<T>>() {
        }.getType());

        System.out.println(jsonParsed.toString());
        return null;
    }

}

第三个 MyJson.java

public class MyJson<T> {
    private int status;
    private T data;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public T getData() {
        return data;
    }

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

并且 User.java

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private long usrId;
    private String usrNm;
    private String usrPwd;
    private String usrEml;

    public User() {

    }

    public long getUsrId() {
        return usrId;
    }

    public void setUsrId(long usrId) {
        this.usrId = usrId;
    }

    public String getUsrNm() {
        return usrNm;
    }

    public void setUsrNm(String usrNm) {
        this.usrNm = usrNm;
    }

    public String getUsrPwd() {
        return usrPwd;
    }

    public void setUsrPwd(String usrPwd) {
        this.usrPwd = usrPwd;
    }

    public String getUsrEml() {
        return usrEml;
    }

    public void setUsrEml(String usrEml) {
        this.usrEml = usrEml;
    }

    @Override
    public String toString() {
        return "User [usrId=" + usrId + ", usrNm=" + usrNm + ", usrPwd="
                + usrPwd + ", usrEml=" + usrEml + "]";
    }
}

我的JSON字符串:

{
    status: 200,
    data: {
        usrId: 2,
        usrNm: "John",
        usrPwd: "123",
        usrEml: "john@test.com"
    }
}

我想将上述json字符串解析为MyJson<T>对象。

我这样做:

MyJson<T> jsonParsed = gson.fromJson(json, new TypeToken<MyJson<T>>() {
            }.getType());

=> GsonMyJson中的User解析为LinkedTreeMap

意思是:Object data = jsonParsed.getData(); => data实例是LinkedTreeMap

我的期望是:data实例是User

但是,当我尝试时:

MyJson<User> jsonParsed = gson.fromJson(json, new TypeToken<MyJson<User>>() {
            }.getType());

gson工作正常。

因此,我想知道如何让gson与第一种方式(使用T而不是User)配合使用,因为我想通过解析器来解析其他对象。

谢谢您的帮助。


1
答案是:由于类型擦除,您无法这样做。 Gson 使用的 TypeToken hack 仅在显式传递类型时才起作用。在运行时,T 的类型完全被擦除。 - Brian Roach
您的解决方案无法解决我的问题。:( - Luc
这不是解决方案,而是再次说明,你不能做你试图要做的事情。 - Brian Roach
谢谢,我解决了这个问题。 :D - Luc
显示剩余2条评论
2个回答

4
@Override
public T parse(String json, Type type) {
    GsonBuilder builder = new GsonBuilder();
    Gson gson = builder.enableComplexMapKeySerialization().create();
    MyJson<T> jsonParsed = gson.fromJson(json, type);

    System.out.println(jsonParsed.toString());
    return null;
}

使用:

User user = myJson.parse(jsonString, new TypeToken<User>() {
        }.getType());

1
这就是我所做的。谢谢先生。 :) - Luc

2
正如其他人所指出的,问题在于 TypeToken 必须用所有具体类型(即不使用任何 T 参数)进行实例化。因此,你需要调用者为你实例化 TypeToken(这里的“你”是指 Parser 类)。
John 接受的答案有效(如果忽略它返回 null 并打印结果的事实),但我认为更好的方法是强制要求返回类型与 Type 参数兼容,像这样:
public T parse(String json, TypeToken<MyJson<T>> typeToken) {
    MyJson<T> deserializedMyJson = gson.fromJson(json, typeToken.getType());
    return deserializedMyJson.getData();
}

这将在编译时强制执行,以确保任何对parse()的调用都传递了正确的TypeToken,因此像下面这样的代码:

A a = parser.parse(jsonString, new TypeToken<MyJson<B>>(){});  // incorrect

如果像这样写(假设parse()方法接受一个Type作为参数),编译时会失败:

A a = parser.parse(jsonString, new TypeToken<MyJson<B>>(){}.getType());  // incorrect too, but will compile

只有在运行时(尝试将parse()执行的B结果转换为类型为A的变量a时)才会失败。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接