Luc
Luc

Reputation: 2805

Convert JSON to Nested Object (generic object) by using GSON

I wanna create an parser for parse JSON by using Gson.

The first IParser.java

public interface IParser<T> {
    public T parse(String json);
}

The second 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;
    }

}

The third 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;
    }
}

And 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 + "]";
    }
}

My JSON String:

{
    status: 200,
    data: {
        usrId: 2,
        usrNm: "John",
        usrPwd: "123",
        usrEml: "[email protected]"
    }
}

I wanna parse above jsonString to MyJson<T> object.

I do:

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

=> Gson parses my User in MyJson to LinkedTreeMap

It mean: Object data = jsonParsed.getData(); => data instance of LinkedTreeMap

What I want: data instance of User

But, when I try:

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

gson works fine.

So I wanna know that How can I make gson works fine with the first way (use T instead of User) because I wanna parse other object by using Parser

Thanks for your help.

Upvotes: 6

Views: 4382

Answers (2)

desseim
desseim

Reputation: 8248

As noted by others the problem is that the TypeToken has to be instantiated with all concrete types (i.e. not parameterized with any T). So you need the caller to instantiate the TypeToken for you ("you" being the Parser class here).

John's accepted answer works (if you ignore the fact that it returns null and print the result instead), but I think it's nicer to enforce the Type parameter compatibility with the returned type, like this:

public T parse(String json, TypeToken<MyJson<T>> typeToken) {
    MyJson<T> deserializedMyJson = gson.fromJson(json, typeToken.getType());
    return deserializedMyJson.getData();
}

And it will enforce at compile time that any call to parse() is passed a correct TypeToken, so that something like

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

will fail at compile time, while something like this (assuming the parse() method takes a Type as parameter):

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

will only fail at runtime (when trying to cast the B result from parse() execution into the a variable of type A).

Upvotes: 2

John
John

Reputation: 66

@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;
}

Using:

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

Upvotes: 4

Related Questions