改造从复杂的JSON响应中获取信息

时间:2018-10-05 10:33:53

标签: android json retrofit retrofit2 json-deserialization

我想检索并转换后的JSON响应并将其转换为对象列表。

这是我的JSON响应示例,仅包含两个元素:

{
   "nhits":395,
   "parameters":{
      "dataset":[
         "sanisettesparis2011"
      ],
      "timezone":"UTC",
      "rows":2,
      "format":"json"
   },
   "records":[
      {
         "datasetid":"sanisettesparis2011",
         "recordid":"cb7aee1791ccce595e97d98fc0f72d05709abf52",
         "fields":{
            "objectid":10,
            "arrondissement":"02",
            "nom_voie":"BOULEVARD DE SEBASTOPOL",
            "geom_x_y":[
               48.864828018946774,
               2.351611260829617
            ],
            "geom":{
               "type":"Point",
               "coordinates":[
                  2.351611260829617,
                  48.864828018946774
               ]
            },
            "y":129375.048287,
            "x":601106.877435,
            "numero_voie":"85",
            "identifiant":"2/102",
            "horaires_ouverture":"6 h - 22 h"
         },
         "geometry":{
            "type":"Point",
            "coordinates":[
               2.351611260829617,
               48.864828018946774
            ]
         },
         "record_timestamp":"2018-09-30T22:00:19+00:00"
      },
      {
         "datasetid":"sanisettesparis2011",
         "recordid":"a47c22cf2fd31ba6b4a1ac6d1d2c699f92ee659a",
         "fields":{
            "objectid":12,
            "arrondissement":"02",
            "nom_voie":"RUE REAUMUR",
            "geom_x_y":[
               48.86679354449764,
               2.34957136374784
            ],
            "geom":{
               "type":"Point",
               "coordinates":[
                  2.34957136374784,
                  48.86679354449764
               ]
            },
            "y":129593.588071,
            "x":600957.183947,
            "numero_voie":"73",
            "identifiant":"2/105",
            "horaires_ouverture":"6 h - 22 h"
         },
         "geometry":{
            "type":"Point",
            "coordinates":[
               2.34957136374784,
               48.86679354449764
            ]
         },
         "record_timestamp":"2018-09-30T22:00:19+00:00"
      }
   ]
}

如您所见,这是一个复杂的JSON响应。我感兴趣的字段如下:

  1. 地区
  2. nom_voie
  3. geom_x_y
  4. numero_voie
  5. horaires_ouverture

我的改装实现如下:

加强保护

public class RetrofitClientInstance {

    private static Retrofit retrofit;
    private static final String BASE_URL = "https://opendata.paris.fr/";

    public static Retrofit getRetrofitInstance() {
        if (retrofit == null) {
            Gson gson =
                    new GsonBuilder()
                            .registerTypeAdapter(Toilet.class, new MyDeserializer())
                            .create();

            retrofit = new retrofit2.Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build();
        }
        return retrofit;
    }

}

MYDESERIALIZER

public class MyDeserializer implements JsonDeserializer<Toilet>
{
    @Override
    public Toiletdeserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
            throws JsonParseException
{
    // Get the "records" element from the parsed JSON
    JsonElement records = je.getAsJsonObject().get("records").getAsJsonArray();

    Log.d("test", records.toString());

    // Deserialize it. You use a new instance of Gson to avoid infinite recursion
    // to this deserializer
    return new Gson().fromJson(records, Toilet.class);
}
}

GETDATASERVICE

 public interface GetDataService {

    @GET("api/records/1.0/search/")
    Call<List<TestListModel>> getAllToilets(@Query("dataset") String dataset, @Query("rows") int numRows);
}

主要呼叫

GetDataService service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
    Call<List<Toilet>> call = service.getAllToilets("sanisettesparis2011", 1);
    call.enqueue(new Callback<List<Toilet>>() {



           @Override
            public void onResponse(Call<List<Toilet>> call, retrofit2.Response<List<Toilet>> response) {
                Log.d(TAG, response.body().toString());
            }

            @Override
            public void onFailure(Call<List<Toilet>> call, Throwable t) {
                t.printStackTrace();
                if (t instanceof IOException) {
                    Toast.makeText(SplashActivity.this, "Network error. Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
                }
                else {
                    Toast.makeText(SplashActivity.this, "Conversion issue", Toast.LENGTH_SHORT).show();
                }
            }
        });

厕所模型

public class Toilet {
    @SerializedName("arrondissement")
    private int arrondissement;
    @SerializedName("nom_voie")
    private String street_name;
    @SerializedName("geom_x_y")
    private double[] coords;
    @SerializedName("numero_voie")
    private String street_number;
    @SerializedName("horaires_ouverture")
    private String opening_hours;

    public Toilet(int arrondissement, String street_name, double[] coords, String street_number, String opening_hours){
        this.arrondissement = arrondissement;
        this.street_name = street_name;
        this.coords = coords;
        this.street_number = street_number;
        this.opening_hours = opening_hours;
       }

    public int getArrondissement() {
        return arrondissement;
    }

    public void setArrondissement(int arrondissement) {
        this.arrondissement = arrondissement;
    }

    public String getStreet_name() {
        return street_name;
    }

    public void setStreet_name(String street_name) {
        this.street_name = street_name;
    }

    public double[] getCoords() {
        return coords;
    }

    public void setCoords(double[] coords) {
        this.coords = coords;
    }

    public String getStreet_number() {
        return street_number;
    }

    public void setStreet_number(String street_number) {
        this.street_number = street_number;
    }

    public String getOpening_hours() {
        return opening_hours;
    }

    public void setOpening_hours(String opening_hours) {
        this.opening_hours = opening_hours;
    }
}

启动我的应用程序时,出现此错误: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

我想这意味着我的解串器没有正确格式化,但是我不知道如何使用这种JSON响应架构正确实现翻新。

此操作的目标是检索具有我之前列出的属性的Toilet对象的列表。

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

在Model类下面复制您的JSON

import com.google.gson.annotations.SerializedName;

import java.util.List;

public class Toilet {
    /**
     * nhits : 395
     * parameters : {"dataset":["sanisettesparis2011"],"timezone":"UTC","rows":2,"format":"json"}
     * records : [{"datasetid":"sanisettesparis2011","recordid":"cb7aee1791ccce595e97d98fc0f72d05709abf52","fields":{"objectid":10,"arrondissement":"02","nom_voie":"BOULEVARD DE SEBASTOPOL","geom_x_y":[48.864828018946774,2.351611260829617],"geom":{"type":"Point","coordinates":[2.351611260829617,48.864828018946774]},"y":129375.048287,"x":601106.877435,"numero_voie":"85","identifiant":"2/102","horaires_ouverture":"6 h - 22 h"},"geometry":{"type":"Point","coordinates":[2.351611260829617,48.864828018946774]},"record_timestamp":"2018-09-30T22:00:19+00:00"},{"datasetid":"sanisettesparis2011","recordid":"a47c22cf2fd31ba6b4a1ac6d1d2c699f92ee659a","fields":{"objectid":12,"arrondissement":"02","nom_voie":"RUE REAUMUR","geom_x_y":[48.86679354449764,2.34957136374784],"geom":{"type":"Point","coordinates":[2.34957136374784,48.86679354449764]},"y":129593.588071,"x":600957.183947,"numero_voie":"73","identifiant":"2/105","horaires_ouverture":"6 h - 22 h"},"geometry":{"type":"Point","coordinates":[2.34957136374784,48.86679354449764]},"record_timestamp":"2018-09-30T22:00:19+00:00"}]
     */

    @SerializedName("nhits")
    private int nhits;
    @SerializedName("parameters")
    private ParametersBean parameters;
    @SerializedName("records")
    private List<RecordsBean> records;

    public int getNhits() {
        return nhits;
    }

    public void setNhits(int nhits) {
        this.nhits = nhits;
    }

    public ParametersBean getParameters() {
        return parameters;
    }

    public void setParameters(ParametersBean parameters) {
        this.parameters = parameters;
    }

    public List<RecordsBean> getRecords() {
        return records;
    }

    public void setRecords(List<RecordsBean> records) {
        this.records = records;
    }

    public static class ParametersBean {
        /**
         * dataset : ["sanisettesparis2011"]
         * timezone : UTC
         * rows : 2
         * format : json
         */

        @SerializedName("timezone")
        private String timezone;
        @SerializedName("rows")
        private int rows;
        @SerializedName("format")
        private String format;
        @SerializedName("dataset")
        private List<String> dataset;

        public String getTimezone() {
            return timezone;
        }

        public void setTimezone(String timezone) {
            this.timezone = timezone;
        }

        public int getRows() {
            return rows;
        }

        public void setRows(int rows) {
            this.rows = rows;
        }

        public String getFormat() {
            return format;
        }

        public void setFormat(String format) {
            this.format = format;
        }

        public List<String> getDataset() {
            return dataset;
        }

        public void setDataset(List<String> dataset) {
            this.dataset = dataset;
        }
    }

    public static class RecordsBean {
        /**
         * datasetid : sanisettesparis2011
         * recordid : cb7aee1791ccce595e97d98fc0f72d05709abf52
         * fields : {"objectid":10,"arrondissement":"02","nom_voie":"BOULEVARD DE SEBASTOPOL","geom_x_y":[48.864828018946774,2.351611260829617],"geom":{"type":"Point","coordinates":[2.351611260829617,48.864828018946774]},"y":129375.048287,"x":601106.877435,"numero_voie":"85","identifiant":"2/102","horaires_ouverture":"6 h - 22 h"}
         * geometry : {"type":"Point","coordinates":[2.351611260829617,48.864828018946774]}
         * record_timestamp : 2018-09-30T22:00:19+00:00
         */

        @SerializedName("datasetid")
        private String datasetid;
        @SerializedName("recordid")
        private String recordid;
        @SerializedName("fields")
        private FieldsBean fields;
        @SerializedName("geometry")
        private GeometryBean geometry;
        @SerializedName("record_timestamp")
        private String recordTimestamp;

        public String getDatasetid() {
            return datasetid;
        }

        public void setDatasetid(String datasetid) {
            this.datasetid = datasetid;
        }

        public String getRecordid() {
            return recordid;
        }

        public void setRecordid(String recordid) {
            this.recordid = recordid;
        }

        public FieldsBean getFields() {
            return fields;
        }

        public void setFields(FieldsBean fields) {
            this.fields = fields;
        }

        public GeometryBean getGeometry() {
            return geometry;
        }

        public void setGeometry(GeometryBean geometry) {
            this.geometry = geometry;
        }

        public String getRecordTimestamp() {
            return recordTimestamp;
        }

        public void setRecordTimestamp(String recordTimestamp) {
            this.recordTimestamp = recordTimestamp;
        }

        public static class FieldsBean {
            /**
             * objectid : 10
             * arrondissement : 02
             * nom_voie : BOULEVARD DE SEBASTOPOL
             * geom_x_y : [48.864828018946774,2.351611260829617]
             * geom : {"type":"Point","coordinates":[2.351611260829617,48.864828018946774]}
             * y : 129375.048287
             * x : 601106.877435
             * numero_voie : 85
             * identifiant : 2/102
             * horaires_ouverture : 6 h - 22 h
             */

            @SerializedName("objectid")
            private int objectid;
            @SerializedName("arrondissement")
            private String arrondissement;
            @SerializedName("nom_voie")
            private String nomVoie;
            @SerializedName("geom")
            private GeomBean geom;
            @SerializedName("y")
            private double y;
            @SerializedName("x")
            private double x;
            @SerializedName("numero_voie")
            private String numeroVoie;
            @SerializedName("identifiant")
            private String identifiant;
            @SerializedName("horaires_ouverture")
            private String horairesOuverture;
            @SerializedName("geom_x_y")
            private List<Double> geomXY;

            public int getObjectid() {
                return objectid;
            }

            public void setObjectid(int objectid) {
                this.objectid = objectid;
            }

            public String getArrondissement() {
                return arrondissement;
            }

            public void setArrondissement(String arrondissement) {
                this.arrondissement = arrondissement;
            }

            public String getNomVoie() {
                return nomVoie;
            }

            public void setNomVoie(String nomVoie) {
                this.nomVoie = nomVoie;
            }

            public GeomBean getGeom() {
                return geom;
            }

            public void setGeom(GeomBean geom) {
                this.geom = geom;
            }

            public double getY() {
                return y;
            }

            public void setY(double y) {
                this.y = y;
            }

            public double getX() {
                return x;
            }

            public void setX(double x) {
                this.x = x;
            }

            public String getNumeroVoie() {
                return numeroVoie;
            }

            public void setNumeroVoie(String numeroVoie) {
                this.numeroVoie = numeroVoie;
            }

            public String getIdentifiant() {
                return identifiant;
            }

            public void setIdentifiant(String identifiant) {
                this.identifiant = identifiant;
            }

            public String getHorairesOuverture() {
                return horairesOuverture;
            }

            public void setHorairesOuverture(String horairesOuverture) {
                this.horairesOuverture = horairesOuverture;
            }

            public List<Double> getGeomXY() {
                return geomXY;
            }

            public void setGeomXY(List<Double> geomXY) {
                this.geomXY = geomXY;
            }

            public static class GeomBean {
                /**
                 * type : Point
                 * coordinates : [2.351611260829617,48.864828018946774]
                 */

                @SerializedName("type")
                private String type;
                @SerializedName("coordinates")
                private List<Double> coordinates;

                public String getType() {
                    return type;
                }

                public void setType(String type) {
                    this.type = type;
                }

                public List<Double> getCoordinates() {
                    return coordinates;
                }

                public void setCoordinates(List<Double> coordinates) {
                    this.coordinates = coordinates;
                }
            }
        }

        public static class GeometryBean {
            /**
             * type : Point
             * coordinates : [2.351611260829617,48.864828018946774]
             */

            @SerializedName("type")
            private String type;
            @SerializedName("coordinates")
            private List<Double> coordinates;

            public String getType() {
                return type;
            }

            public void setType(String type) {
                this.type = type;
            }

            public List<Double> getCoordinates() {
                return coordinates;
            }

            public void setCoordinates(List<Double> coordinates) {
                this.coordinates = coordinates;
            }
        }
    }
}

在从改造中获得响应时,会得到这样的数据

在这里我使用static位置获取数据

GetDataService service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
    Call<List<Toilet>> call = service.getAllToilets("sanisettesparis2011", 1);
    call.enqueue(new Callback<List<Toilet>>() {



           @Override
            public void onResponse(Call<List<Toilet>> call, retrofit2.Response<List<Toilet>> response) {
                Log.d(TAG, response.body().toString());


 String arrondissement_0=response.body().getRecords().get(0).getFields().getArrondissement();
                    String arrondissement_1=response.body().getRecords().get(1).getFields().getArrondissement();

                    String nom_voie_0=response.body().getRecords().get(0).getFields().getNomVoie();
                    String nom_voie_1=response.body().getRecords().get(1).getFields().getNomVoie();

                    double geom_x_y_0=response.body().getRecords().get(0).getFields().getGeomXY().get(0);
                    double geom_x_y_1=response.body().getRecords().get(0).getFields().getGeomXY().get(1);

                    String numero_voie_0=response.body().getRecords().get(0).getFields().getNumeroVoie();
                    String numero_voie_1=response.body().getRecords().get(1).getFields().getNumeroVoie();

                    String horaires_ouverture_0=response.body().getRecords().get(0).getFields().getHorairesOuverture();
                    String horaires_ouverture_1=response.body().getRecords().get(1).getFields().getHorairesOuverture();
            }

            @Override
            public void onFailure(Call<List<Toilet>> call, Throwable t) {
                t.printStackTrace();
                if (t instanceof IOException) {
                    Toast.makeText(SplashActivity.this, "Network error. Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
                }
                else {
                    Toast.makeText(SplashActivity.this, "Conversion issue", Toast.LENGTH_SHORT).show();
                }
            }
        });

要为任何响应创建模型类,您可以使用pluginGsonFormat 步骤:创建空类>按alt + insert>选择GsonFormat>粘贴JSON>完成 检查这张图片 enter image description here

答案 1 :(得分:0)

首先将您的JSON响应放在JsonSchema2pojo。它将为您提供GSON模型。将这些模型添加到您的项目中。 然后,您可以获取所需的字符串。

  GetDataService apiInterface = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class); 
            //Example ~ ModelClassName
            Call<Example> call = apiInterface.getAllToilets( 
                    dataset, 
                    numRows); 

            call.enqueue(new Callback<Example>() { 
                @Override 
                public void onResponse(Call<Example> call, Response<Example> response) {
                    if (response.isSuccessful()) { 
                       Example exam = response.body();
                     String arrondissement = exam.getRecords().getFields().getArrondissement();
                   //Same for others
                    } else { 
                        Toasty.error(Main.this,
                                "Error => " + response.errorBody(), Toast.LENGTH_SHORT).show(); 
                    }
                }
                @Override
                public void onFailure(Call<Example> call, Throwable t) {
                    call.cancel(); 
                    Toasty.error(Main.this,
                            "Error: "+ t.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); 
                } 

在需要数据的地方添加它。

答案 2 :(得分:0)

“记录”对象是厕所列表,因此您应该添加另一个仅包含厕所列表的模型(例如,名为“厕所”)