web-dev-qa-db-fra.com

Utilisation de Retrofit pour accéder aux tableaux JSON

Je pensais comprendre comment faire cela, mais évidemment pas. J'ai mon API de Flickr, qui commence comme suit:

jsonFlickrApi({
   "photos":{
      "page":1,
      "pages":10,
      "perpage":100,
      "total":1000,
      "photo":[
         {
            "id":"12567883725",
            "owner":"74574845@N05",
            "secret":"a7431762dd",
            "server":"7458",
            "farm":8,
            "title":"",
            "ispublic":1,
            "isfriend":0,
            "isfamily":0,
            "url_l":"http:\/\/farm8.staticflickr.com\/7458\/12567883725_a7431762dd_b.jpg",
            "height_l":"683",
            "width_l":"1024"
         }

Maintenant, les informations dont j'ai besoin sont issues du tableau de photos. Ce que j'ai essayé de faire est la suivante:

interface ArtService {

    @GET("/services/rest/?method=flickr.photos.getRecent&extras=url_l&owner_name&format=json")
    PhotosResponse getPhotos();

    public class PhotosResponse {
        Photos photos;
    }

    public class Photos {
        List<Arraz> photo;
    }

    public class Arraz {
        int id;
        String title;
        String owner;
        String url_l;
    }
}

Très clairement que je semble manquer le point, cependant je ne suis pas sûr de savoir comment obtenir l'information.

37
K20GH

Un coup d’œil aux documents de Retrofit indique qu’il utilise Gson pour convertir JSON en classes Java. Cela signifie que vous avez besoin d'une hiérarchie de classes en Java correspondant au JSON. Le vôtre… non.

Le JSON renvoyé est un objet avec un seul champ "photos" qui contient un objet.

{ "photos" : { ... } }

Ainsi, votre classe de niveau supérieur serait une classe Java avec un seul champ:

public class PhotosResponse {
    private Photos photos;

    // getter/setter
}

Et ce type Photos serait une autre classe qui correspond au JSON pour l'objet que le champ contient:

{ "page":1, "pages":10, ... }

Donc vous auriez:

public class Photos {
    private int page;
    private int pages;
    private int perpage'
    private int total;
    private List<Photo> photo;

    // getters / setters
}

Ensuite, vous créeriez une classe Photo pour correspondre à la structure de l'objet dans ce tableau interne. Gson mappera ensuite le JSON renvoyé de manière appropriée.

42
Brian Roach

Je suggérerais d’utiliser http://www.jsonschema2pojo.org . Vous pouvez coller votre JSON et il générera les POJO pour vous.

Cela devrait faire l'affaire.

47
LaSombra

La réponse acceptée est correcte mais nécessite la construction d'une classe PhotoResponse ne contenant qu'un seul objet. Ceci la solution suivante, nous avons seulement besoin de créer la classe Photos et une certaine stérilisation.

Nous créons un JsonDeserializer:

class PhotosDeserializer implements JsonDeserializer<Photos>
{
    @Override
    public Photos deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        JsonElement content = json.getAsJsonObject().get("photos");

        return new Gson().fromJson(content, Photos.class);

    }

}

Maintenant, nous créons notre objet gson personnalisé dans RestAdapter de Retrofit:

    Gson gson = new GsonBuilder()
                    .registerTypeAdapter(Photos.class, new PhotosDeserializer())
                    .create();

Et puis nous plaçons le convertisseur dans l'adaptateur de conversion:

 RestAdapter restAdapter = new RestAdapter.Builder()
                                            .setEndpoint(ArtService.ENDPOINT)
                                            .setConverter(new GsonConverter(gson))
                                            .build();

Et l'interface ressemblerait à ceci:

@GET("/?method="+METHOD_GET_RECENT+"&api_key="+API_KEY+"&format=json&nojsoncallback=1&extras="+EXTRAS_URL)
public void getPhotos(Callback<Photos> response);

De cette façon, nous obtenons l'objet Photos sans avoir à créer de classe PhotosResponse. Nous pouvons l'utiliser comme ceci:

ArtService artService = restAdapter.create(ArtService.class);
artService.getPhotos(new Callback<Photos>() {
    @Override
    public void success(Photos photos, Response response) {

        // Array of photos accessing by photos.photo

   }

   @Override
   public void failure(RetrofitError error) {


    }
});
10
FOMDeveloper

Vous devriez pouvoir accéder directement à com.google.gson.JsonObject depuis Retrofit et accéder à n’importe quel champ de votre choix . Si vous n’êtes intéressé que par le tableau Photo, une solution comme celle-ci devrait fonctionner:

interface ArtService {
    @GET("/services/rest/?method=flickr.photos.getRecent&extras=url_l&owner_name&format=json")
    JsonObject getPhotos();

    public class Photo {
         int id;
         String title;
         String owner;
         String url_l;
    }
}

Et lorsque vous appelez le service, exécutez simplement JsonObject pour obtenir ce que vous voulez:

    JsonObject json = mRestClient.getArtService().getPhotos();
    List<ArtService.Photo> photos = new Gson().fromJson(json.getAsJsonObject("photos").get("photo").toString(), new TypeToken<List<ArtService.Photo>>() {}.getType());

Bien sûr, tous les contrôles de santé mentale sont laissés à vous.

2
Gomino

Comme déjà quelques réponses sont au-dessus que vous pouvez utiliser. Mais comme à mon avis, utilisez ceci. Créez une classe de photos avec toutes les variables indiquées dans l'objet photos et créez un getter setter, créez une classe de photos avec la liste des photos et créez un getter setter de cette liste dans la classe Photos. Ci-dessous le code donné. 

public static class Photos {

        @JsonProperty("page")
        private double page;
        @JsonProperty("pages")
        private double pages;
        @JsonProperty("perpage")
        private double perpage;
        @JsonProperty("total")
        private double total;

        @JsonProperty("photo")
        private List<Photo> photo;


        public double getPage() {
            return page;
        }

        public void setPage(double page) {
            this.page = page;
        }

        public double getPages() {
            return pages;
        }

        public void setPages(double pages) {
            this.pages = pages;
        }

        public double getPerpage() {
            return perpage;
        }

        public void setPerpage(double perpage) {
            this.perpage = perpage;
        }

        public double getTotal() {
            return total;
        }

        public void setTotal(double total) {
            this.total = total;
        }
    }

    public static class Photo {
        // refer first class and declare all variable of photo array and generate getter setter.
    }
0
Vid