Search code examples
javajsonspringresttemplate

How to Parse only a portion of a web JSON in Java using RestTemplate?


I'm trying to get the first 5 articles from this API: https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21

My code works perfectly for now, but it parses all 10 articles of NewsAPI.

The code is:

public News parse() {

    return restTemplate.getForObject
                    ("https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21", News.class);

    }
}

and the result is:

{
    "totalResults": 10,
    "articles": [
        {
            "source": {
                "id": "bbc-news",
                "name": "BBC News"
            },
            "author": "BBC News",
            "title": "Measles returns to four European nations, WHO says",
            "url": "http://www.bbc.co.uk/news/health-49507253"
        },
    etc......

Of course, i created the classes that describe Article, Source and News. News has a List of Article.

I just want to parse the first five articles and save them into a List. I know I have to use a For cycle, but how can i do that? I tried with this code:

public News parseFive() {
    List<Article> articleList = null;

    for(int i = 0; i<5; i++) {
        articleList = Arrays.asList(
        new Article(restTemplate.getForObject
                                ("https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21", Article.class)));
    }
    News news = new News();
    news.setArticles(articleList);
    return news;
}

The News class is:

public class News {

    private int totalResults;

    private List<Article> articles;

    public News() {

    }

    public int getTotalResults() {
        return totalResults;
    }

    public void setTotalResults(int totalResults) {
        this.totalResults = totalResults;
    }

    public List<Article> getArticles() {
        return articles;
    }

    public void setArticles() {
        this.articles = articles;
    }
}

and the result is:

{
    "totalResults": 0,
    "articles": [
        {
            "source": null,
            "author": null,
            "title": null,
            "url": null
        }
    ]
}

Where is the problem? Maybe because the first class who finds is not Article but is News? Thanks everyone for the effort.


Solution

  • When you are using RestTemplate.getForObject you are technically parsing the whole response: Spring reads all the bytes and uses JSON parser (Jackson) to create an object. Your for loop, which is covered later, only filters out elements past 5th. If you really want to parse only first 5 articles, you should consider using Jackson Streaming API. It is quiet problematically to use with RestTemplate, read this answer for more info.

    Now let's try to fix your parseFive.

    First, create a class to capture whole response:

    public class Response {
        private String status;
        private Integer totalResults;
        private List<Artice> articles;
    
        // Getters & Setters
    }
    

    Now, get first five articles:

    public News parseFive() {
        final Response response = restTemplate
            .getForObject("https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21", Response.class);
        final News news = new News();
    
        news.setArticles(response.articles.stream().limit(5).collect(Collectors.toList());
    
        return news;
    }
    

    You have not provided your News class, probably it is the same as response. Then, the code may look like:

    public News parseFive() {
        final News news = restTemplate
            .getForObject("https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=19acc3a371d145ecb37a093f9985ea21", Response.class);
    
        news.setArticles(news.articles.stream().limit(5).collect(Collectors.toList());
    
        return news;
    }