DaveNOTDavid
DaveNOTDavid

Reputation: 1803

Error parsing JSON data to an array using GSON

Before you assume that this question is a duplicate based on its title, I must say that I couldn't find any solutions out there for my specific problem. However, I'd appreciate it if you could suggest some links! That said, my problem is that I keep getting the following GSON exception:

07-24 10:12:44.713 2540-2603/com.davenotdavid.dndheadlines W/System.err: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

I understand that I'm somehow passing in a JSON object as opposed to an array, but what I don't understand is how it's not working based on the following Utility class that basically has helper methods to parse and extract JSON data from a JSON array using the OkHttpClient and GSON libraries, and then returns a list of extracted data back to the calling class:

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class QueryUtils {
    public static List<Article> fetchArticleData(String requestUrl) {
        String jsonResponse = "";
        try {
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(requestUrl)
                    .build();
            Response response = okHttpClient.newCall(request).execute();
            jsonResponse = response.body().string();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return extractDataFromJson(jsonResponse);
    }

    private static List<Article> extractDataFromJson(String jsonResponse) {
        if (jsonResponse == null || jsonResponse.isEmpty()) {
            return null;
        }

        List<Article> articlesList = new ArrayList<>();

        ArticleResponse[] articleResult = new ArticleResponse[0];
        try {
            Gson gson = new Gson();
            Type collectionType = new TypeToken<Collection<ArticleResponse>>(){}.getType();

            // *** Exception is thrown here ***
            Collection<ArticleResponse> enums = gson.fromJson(jsonResponse, collectionType);

            articleResult = enums.toArray(new ArticleResponse[enums.size()]);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (articleResult.length != 0) {
            for (int i = 0; i < articleResult.length; i++) {
                ArticleResponse article = articleResult[i];
                articlesList.add(new Article(
                        article.getTitle(),
                        article.getUrl(),
                        article.getUrlToImage(),
                        article.getPublishedAt()));
            }
        }

        return articlesList;
    }
}

As you'll notice that the exception is thrown in the following line of code:

Collection<ArticleResponse> enums = gson.fromJson(jsonResponse, collectionType);

Here's the ArticleResponse class I generated using GsonFormat:

public class ArticleResponse {

    /**
     * author : Annalee Newitz
     * title : First glimpse of Steven Spielberg’s new movie, Ready Player One
     * description : This trailer introduces us to a VR dystopia, and has the greatest soundtrack ever.
     * url : https://arstechnica.com/the-multiverse/2017/07/first-glimpse-of-steven-spielbergs-new-movie-ready-player-one/
     * urlToImage : https://cdn.arstechnica.net/wp-content/uploads/2017/07/RPO-1000x437-nbv413pszkz7s29g3blop7i6ymcv84f9mtwmvt1xxk-760x380.png
     * publishedAt : 2017-07-23T17:13:56Z
     */

    private String title;
    private String url;
    private String urlToImage;
    private String publishedAt;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {this.title = title;}

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUrlToImage() {
        return urlToImage;
    }

    public void setUrlToImage(String urlToImage) {
        this.urlToImage = urlToImage;
    }

    public String getPublishedAt() {
        return publishedAt;
    }

    public void setPublishedAt(String publishedAt) {
        this.publishedAt = publishedAt;
    }
}

A sample JSON response from a network call in the Utility class is as follows:

{
    "status": "ok",
    "source": "ars-technica",
    "sortBy": "top",
    "articles": [{
        "author": "Eric Berger",
        "title": "Elon Musk’s Mars rocket may be about to lose half of its engines",
        "description": "Downscaling the Mars booster suggests that Musk may be bending toward reality.",
        "url": "https://arstechnica.com/science/2017/07/elon-musk-drops-an-important-hint-about-his-revised-mars-rocket/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/29937260386_45ba70fb85_h-1440x614-760x380.jpg",
        "publishedAt": "2017-07-24T13:12:01Z"
    }, {
        "author": null,
        "title": "Hour of Devastation review: The evil elder dragon god-pharaoh has arrived. RIP.",
        "description": "Plus, a look at the major changes coming to future Magic: the Gathering sets.",
        "url": "https://arstechnica.com/gaming/2017/07/magic-hour-of-devastation-review/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/401538_CN-copy-760x380.jpg",
        "publishedAt": "2017-07-24T13:00:52Z"
    }, {
        "author": "Annalee Newitz",
        "title": "Season 2 of Stranger Things looks even creepier and more intense",
        "description": "The Upside Down is back, and it looks like it's about to eat the world.",
        "url": "https://arstechnica.com/the-multiverse/2017/07/season-2-of-stranger-things-looks-even-creepier-and-more-intense/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/landscape-1486986380-stranger-things-mike-wheeler-2-760x380.jpg",
        "publishedAt": "2017-07-23T23:20:39Z"
    }, {
        "author": "Annalee Newitz",
        "title": "First glimpse of Steven Spielberg’s new movie, Ready Player One",
        "description": "This trailer introduces us to a VR dystopia, and has the greatest soundtrack ever.",
        "url": "https://arstechnica.com/the-multiverse/2017/07/first-glimpse-of-steven-spielbergs-new-movie-ready-player-one/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/RPO-1000x437-nbv413pszkz7s29g3blop7i6ymcv84f9mtwmvt1xxk-760x380.png",
        "publishedAt": "2017-07-23T17:13:56Z"
    }, {
        "author": null,
        "title": "New book explores how protesters—and governments—use Internet tactics",
        "description": "The protest frontiers are changing. An entrenched researcher explains why they work.",
        "url": "https://arstechnica.com/tech-policy/2017/07/twitter-and-tear-gas-book-explores-new-world-of-digital-protest/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/Screen-Shot-2017-07-22-at-1.17.15-PM-760x380.png",
        "publishedAt": "2017-07-23T15:00:02Z"
    }, {
        "author": "Nathan Mattise",
        "title": "Maybe The Americans is quietly a technophile love letter to the 1980s",
        "description": "Joel Fields and Joe Weisberg talk handheld football, spy tech, mail robot, and more.",
        "url": "https://arstechnica.com/the-multiverse/2017/07/maybe-the-americans-is-quietly-a-technophile-love-letter-to-the-1980s/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/AmericansFootball-600x380.jpg",
        "publishedAt": "2017-07-23T14:30:15Z"
    }, {
        "author": "Sam Machkovech",
        "title": "Dockless bike sharing lands in Seattle—and leads us down unsavory alleyways",
        "description": "Now in Seattle: two services, 1,000 bikes, and a shoulder shrug at helmet laws.",
        "url": "https://arstechnica.com/business/2017/07/dockless-bike-sharing-lands-in-seattle-and-leads-us-down-unsavory-alleyways/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/IMAG3645-760x380.jpg",
        "publishedAt": "2017-07-23T14:00:32Z"
    }, {
        "author": null,
        "title": "Level up: How video games evolved to solve significant scientific problems",
        "description": "Science, your chance to use all that time spent gaming for the greater good.",
        "url": "https://arstechnica.com/gaming/2017/07/level-up-how-video-games-evolved-to-solve-significant-scientific-problems/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/GettyImages-134429675-760x380.jpg",
        "publishedAt": "2017-07-23T13:25:25Z"
    }, {
        "author": "John Timmer",
        "title": "We’ve screwed up the coasts so badly that an invasive species is a plus",
        "description": "When native species are gone, an invasive one can provide ecosystem services.",
        "url": "https://arstechnica.com/science/2017/07/weve-screwed-up-the-coasts-so-badly-that-an-invasive-species-is-a-plus/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/Gracilaria-vermiculophylla-760x380.jpg",
        "publishedAt": "2017-07-23T12:00:53Z"
    }, {
        "author": "Megan Geuss",
        "title": "German energy company wants to build flow batteries in old natural gas caverns",
        "description": "Research for a massive redox flow battery is underway.",
        "url": "https://arstechnica.com/business/2017/07/german-energy-company-wants-to-build-flow-batteries-in-old-natural-gas-caverns/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/20170612-b4p-english-760x380.jpg",
        "publishedAt": "2017-07-22T15:00:22Z"
    }]
}

Upvotes: 0

Views: 2309

Answers (2)

Amit Kumar
Amit Kumar

Reputation: 1458

The reason why you are getting this error is because your json response begins with a json object and you are telling json to parse the articles response which is an array.

{
    "status": "ok",
    "source": "ars-technica",
    "sortBy": "top",
    "articles": [{
        "author": "Eric Berger",
        "title": "Elon Musk’s Mars rocket may be about to lose half of its engines",
        "description": "Downscaling the Mars booster suggests that Musk may be bending toward reality.",
        "url": "https://arstechnica.com/science/2017/07/elon-musk-drops-an-important-hint-about-his-revised-mars-rocket/",
        "urlToImage": "https://cdn.arstechnica.net/wp-content/uploads/2017/07/29937260386_45ba70fb85_h-1440x614-760x380.jpg",
        "publishedAt": "2017-07-24T13:12:01Z"
    },
    ....
    }]   
}

So in order to do that, you need to first retrieve the articles json array and then pass it to gson.fromJson() method. You can do that by doing some change in fetchArticleData() method -

public static List<Article> fetchArticleData(String requestUrl) {
    String jsonResponse = "";
    try {
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(requestUrl)
                .build();
        Response response = okHttpClient.newCall(request).execute();
        jsonResponse = response.body().string();
        JSONObject jsonObject = new JSONObject(jsonResponse);
        JSONArray articleArray = jsonObject.getJSONArray("articles");
        return extractDataFromJson(articleArray.toString());
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

Upvotes: 3

Diego Alvis
Diego Alvis

Reputation: 1855

You cannot convert your jsonObject in an Array you must have a jsonArray to do this. Simply add this lines:

JsonObject jsonObject = gson.fromJson(jsonResponse, JsonObject.class);
String articlesArrayResponse = jsonObject.getAsJsonArray("articles").getAsString();

before your exception happens. Obviously you must change the argument in that line for this:

Collection<ArticleResponse> enums = gson.fromJson(articlesArrayResponse, collectionType);

I hope it helps you!

Upvotes: 3

Related Questions