17

如何使用 Gson 解析这个 JSON?我有一个包含多种对象类型的数组,但我不知道我需要创建什么样的对象来保存这个结构。我无法更改 json 消息(我不控制服务器)。

唯一起作用的类(有点)是这个

public class Response {
    private List<Object> tr;
    private int results;

    (...)

}

JSON 消息(注意具有多种对象类型的数组。)

{
   "tr":
   [
       {
           "a":
           {
               "userId": "112"
           }
       },
       {
           "b":
           {
               "userId": "123",
               "address":"street dummy" 
           }
       },
       {
           "a":
           {
               "userId": "154"
           }
       }
   ],
"results":3
}
4

5 回答 5

21

Gson 用户指南明确涵盖了这一点:

https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Collection-with-Objects-of-Arbitrary-Types

您有一个对象,其字段tr是包含任意类型的数组。

用户指南解释说您不能直接反序列化这样的结构,并建议:

使用 Gson 的解析器 API(低级流解析器或 DOM 解析器 JsonParser)解析数组元素,然后对每个数组元素使用 Gson.fromJson()。这是首选方法。

在您的情况下......这实际上取决于该数组中可能有哪些对象。如果他们都将拥有相同的内在对象,你会想要做类似的事情......

List<MyUserPojo> list = new ArrayList<MyUserPojo>();
JsonArray array = parser.parse(json).getAsJsonObject().getAsJsonArray("tr");
for (JsonElement je : array)
{
    Set<Map.Entry<String,JsonElement>> set = je.getAsObject().entrySet();
    JsonElement je2 = set.iterator().next().getValue();

    MyUserPojo mup = new Gson().fromJson(je2, MyUserPojo.class);
    list.add(mup);
}

当然,这需要在您的实际对象的自定义反序列化器中,该对象将具有trandresults字段。

class MyPojo
{
    List<MyUserPojo> userList;
    int results; 
}

class MyUserPojo
{
    String userId;
    String address;
}

class MyDeserializer implements JsonDeserializer<MyPojo>
{
    @Override
    public MyPojo deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
                              throws JsonParseException
    {
        List<MyUserPojo> list = new ArrayList<MyUserPojo>();
        JsonArray array = je.getAsJsonObject().getAsJsonArray("tr");
        for (JsonElement je2 : array)
        {
            Set<Map.Entry<String,JsonElement>> set = je2.getAsObject().entrySet();
            JsonElement je3 = set.iterator().next().getValue();                 

            MyUserPojo mup = new Gson().fromJson(je3, MyUserPojo.class);
            list.add(mup);
        }

        MyPojo mp = new MyPojo();
        mp.tr = list;
        mp.results = je.getAsObject().getAsJsonPrimitive("results").getAsInt();

        return mp;
    }
}

现在一切就绪 - 您可以使用该反序列化器并创建您的对象:

Gson gson = new GsonBuilder()
                .registerTypeAdapter(MyPojo.class, new MyDeserializer())
                .build();

MyPojo mp = gson.fromJson(json, MyPojo.class);

如果a,b等很重要……那么,您必须弄清楚这一点。但是上面的内容应该能让你很好地理解处理 JSON 结构需要什么。

为了完整起见,解决此问题的唯一“hacky”方法是,如果这些类型的数量相当有限,并且内部对象的字段也相当有限。您可以创建一个包含所有可能性的 POJO:

class MyPojo 
{
    MySecondPojo a;
    MySecondPojo b;
    ...
    MySecondPojo f;
}

class MySecondPojo
{
    String userId;
    String address;
    ...
    String someOtherField;
}

当 Gson 反序列化 JSON 时,它会将 POJO(s) 中所有缺失的字段设置为null. 你现在tr可以在你的 POJO 中有一个List或一个数组。再次强调一下,这真的很hacky并且是错误的方法,但我想我会解释直接解析该数组需要什么。

于 2013-02-05T19:37:50.840 回答
5

我从每个答案中挑选一些东西并这样做:

响应对象

public class Response {
    private List<Users> tr;
    private int results;

    (...)
}

普通用户

public class User {
    public static final int TYPE_USER_A =0;
    public static final int TYPE_USER_B =1;
    private String userId;
    private int type;
    (...)
}

一个

public class a extends User {
    private String location;
    (...) 
}

public class b extends User { 
    private String adress;   
    (...)
}

解析方法

private Response buildResponseObject(String response) {
        Response tls = new Response();
        List<Users> users = new ArrayList<users>();
        User u;

        try {
            JSONObject object = new JSONObject(response);
            tls.setResults(object.getInt("results"));
            JSONArray array = object.getJSONArray("tr");

            for (int i = 0; i < array.length(); i++) {
                JSONObject trs = array.getJSONObject(i);

                if (trs.has("a")) {
                    String json = trns.getString("a");
                    A a = new Gson().fromJson(json,A.class);
                    a.setType(User.TYPE_USER_A);
                    users.add(a);

                } else if (trs.has("b")) {
                    String json = trs.getString("b");
                    B b= new Gson().fromJson(json,B.class);
                    B.setType(User.TYPE_USER_B);
                    users.add(b);
                }
            }

            tls.setUsers(users);

        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return tls;
    }

这并不像我想要的那样优雅,并将本机 JsonObjects 与 Gson 方法混合,但对我有用。

于 2013-02-06T10:52:29.037 回答
2

在这里试试这个代码:

public class Address {
    public String userId;
    public String address;
    // ...
}

public class Response {
    private HashMap<String, Address> tr;
    private int results;
    // ...
}

用法:

String json = "{\n  \"tr\":\n  {\n    \"a\": {\n       \"userId\": \"112\"\n    },\n    \"b\": {\n       \"userId\": \"123\",\n       \"address\":\"street dummy\"\n    },\n    \"c\": {\n       \"userId\": \"154\"\n    }\n  },\n  \"results\":3\n}";

Response users = new Gson().fromJson(json, Response.class);

如您所见,我需要修改结构:

{
  "tr":
  {
    "a": {
       "userId": "112"
    },
    "b": {
       "userId": "123",
       "address":"street dummy"
    },
    "c": {
       "userId": "154"
    }
  },
  "results":3
}

但不幸的是,我没有设法允许多个密钥。现在我不知道如何解决这个问题。

于 2013-02-05T18:00:19.767 回答
0

我认为此链接可能会对您有所帮助: https ://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples

基本上,为您的“对象”(我猜是用户类型)创建一个类,然后使用 Gson 的反序列化代码,如下所示:

Type collectionType = new TypeToken<Collection<User>>(){}.getType();
Collection<User> users= gson.fromJson(json, collectionType);
于 2013-02-05T17:54:45.393 回答
-2

您可以为 json 对象创建相应的 java 类。整数、字符串值可以按原样映射。Json 可以这样解析——

Gson gson = new GsonBuilder().create();
Response r = gson.fromJson(jsonString, Response.class);

这是一个示例-http ://rowsandcolumns.blogspot.com/2013/02/url-encode-http-get-solr-request-and.html

于 2013-02-11T19:02:17.730 回答