【问题标题】:Parsing object with dynamic key through gson通过gson用动态键解析对象
【发布时间】:2016-09-14 10:09:47
【问题描述】:

正如标题所说,我正在尝试解析一个对象,其键是动态字符串。我已经看了很长时间的一些答案,发现 1.this、2.this 和 3.this

供您参考,我对 Java 有点陌生,这是我第一次使用 Json 数据和解析

Json 响应如下所示:

{"Narcos": {"episodes": [{"season": 2, "name": "Episode #2.1", "number": 1}, {"season": 2, "name": "Episode #2.10", "number": 10}, {"season": 2, "name": "Episode #2.2", "number": 2}, {"season": 2, "name": "Episode #2.3", "number": 3}, {"season": 2, "name": "Episode #2.4", "number": 4}, {"season": 2, "name": "Episode #2.5", "number": 5}, {"season": 2, "name": "Episode #2.6", "number": 6}, {"season": 2, "name": "Episode #2.7", "number": 7}, {"season": 2, "name": "Episode #2.8", "number": 8}, {"season": 2, "name": "Episode #2.9", "number": 9}, {"season": 1, "name": "Descenso", "number": 1}, {"season": 1, "name": "Despegue", "number": 10}, {"season": 1, "name": "Explosivos", "number": 6}, {"season": 1, "name": "La Catedral", "number": 9}, {"season": 1, "name": "La Gran Mentira", "number": 8}, {"season": 1, "name": "The Men of Always", "number": 3}, {"season": 1, "name": "The Palace in Flames", "number": 4}, {"season": 1, "name": "The Sword of Sim\u00f3n Bolivar", "number": 2}, {"season": 1, "name": "There Will Be a Future", "number": 5}, {"season": 1, "name": "You Will Cry Tears of Blood", "number": 7}], "year": 2015}}

动态键,在本例中是“毒枭”。它基本上是您想要剧集的节目的名称。

我尝试了不同的方法。 对于第一个链接,解析代码如下:

ApiTest.class

Type mapType = new  TypeToken<Map<String, Serie> >() {}.getType(); // define generic type

    Map<String, Serie> serie = gson.fromJson(jsonString, mapType);

Serie.class

 public class Serie {

    private Episodes episodes;

Episodes.class

public class Episodes {

    private Episode[] episode;
    private int year;

剧集类

public class Episode {

    private int season;
    private String name;
    private int number;

当我使用第一种方法时,我得到了这个错误

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 41 path $..episodes
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:187)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
    at com.google.gson.Gson.fromJson(Gson.java:887)
    at com.google.gson.Gson.fromJson(Gson.java:852)
    at com.google.gson.Gson.fromJson(Gson.java:801)
    at testing.ApiTest.main(ApiTest.java:114)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 41 path $..episodes
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:213)
    ... 9 more

当我尝试根据其他两个线程解析数据时,我创建了一个这样的响应类:

PoroResponse.class

public class PoroResponse {

    private Map<String, Serie> serie;

并将 ApiTest.class 中的代码更改为:

PoroResponse poro = gson.fromJson(jsonString, PoroResponse.class);

并试图通过这个来获得一个可以使用的数组:

Episode[] episodes = poro.get(poro).getSerie().getEpisodes().getEpisode();

我也试过这样解析:

Object o = new Gson().fromJson(json, Object.class);

但在最后两种情况下,要么我的 Serie 对象为 NULL,要么我得到一个具有 NULL 值的 LinkedTreeMap。

有人能指出我正确的方向吗?自 2 天以来,我一直被困在这个问题上,老实说,我不知道如何解决它。

【问题讨论】:

    标签: java json api parsing gson


    【解决方案1】:

    也许你可以试试这个: 剧集类

        public class Episode {
    
        @SerializedName("season")
        @Expose
        private Integer season;
        @SerializedName("name")
        @Expose
        private String name;
        @SerializedName("number")
        @Expose
        private Integer number;
    
    
        public Integer getSeason() {
            return season;
        }
    
    
        public void setSeason(Integer season) {
            this.season = season;
        }
    
    
        public String getName() {
            return name;
        }
    
    
        public void setName(String name) {
            this.name = name;
        }
    
    
        public Integer getNumber() {
            return number;
        }
    
    
        public void setNumber(Integer number) {
            this.number = number;
        }
    
     }
    

    然后是串行类:

        public class Serial {
    
        @SerializedName("episodes")
        @Expose
        private List<Episode> episodes = new ArrayList<Episode>();
        @SerializedName("year")
        @Expose
        private Integer year;
    
        public List<Episode> getEpisodes() {
            return episodes;
        }
    
    
        public void setEpisodes(List<Episode> episodes) {
            this.episodes = episodes;
        }
    
    
        public Integer getYear() {
            return year;
        }
    
    
        public void setYear(Integer year) {
            this.year = year;
        }
    
     }
    

    然后要使用来自 JSON 的动态键生成 JAVA 对象,只需运行以下命令:

    Type type = new TypeToken<Map<String, Serial>>() {
            }.getType();
    Map<String, Serial> result = new Gson()
                    .fromJson(new InputStreamReader(new ByteArrayInputStream(jsonString.getBytes())), type);
    

    要获取例如 Narcos 序列信息,您需要这样写:

    Serial narcosSerial = result.get("Narcos");
    

    【讨论】:

    • 感谢您的意见。我应该补充说 Narcos 是动态键。它根据对 API 的请求而变化。因此,它始终是您请求的节目的名称。这是 API 的 URL,如果它可能有帮助的话。我将编辑我的问题以使其更清晰。
    • 非常感谢。这正是我一直在寻找的。我仍在试图弄清楚为什么我只需要这两个类。但是代码可以按我的意愿工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多