0

I'm making a webapp using Giant Bomb API.

I'm stuck because I need to get a list of search results from GET request (using Unirest) and then convieniently convert it to a List of Objects called suggestions.

Here's where my problem is:

private List<Suggestion> suggestions = new ArrayList<>();

public List<Suggestion> searchGames(){

    HttpResponse<String> request;
    try {
    request = Unirest.get("http://giantbomb.com/api/search/?api_key=xxxxxxxxxxxxxxxxxxxxxxxxx&format=json&resources=game&limit=10&field_list=name&query=creed")
                .header("Accept", "application/json")
                .asString();

    String requestString = request.toString(); //I can get my request as String, but that doesnt change much, I guess

    //>>> the problematic part <<<

    return suggestions;
}

I'm missing something that would allow me to convert JSON response from Unirest to a List. Here's what I tried:

  • GSON - problems with JSON format (there's some data in the beginning of JSON because of the fields with Limit, Offset and so on)
  • Object Mapper (Unirest/Jackson) - problems since I get httpResponse instead of String/Object/JsonNode etc.
  • using JSONObject, JSONArray and for loop - no luck as well.

My JSON from Unirest call looks pretty much like this:

 {
        "error": "OK",
        "limit": 10,
        "offset": 0,
        "number_of_page_results": 1,
        "number_of_total_results": 3,
        "status_code": 1,
        "results": [
            {
                "name": "Assassin's Creed",
                "resource_type": "game"
            },
            {
                "name": "The Creed",
                "resource_type": "game"
            },
            {
                "name": "Assassin's Creed: Lost Legacy",
                "resource_type": "game"
            }
        ]
}

I have a similar solution for Game class where I display List called games.

private List<Game> games = new ArrayList<>();

public List<Game> getAllGames(){
    return games;
}

I populate this list using a GET requests where I enter id and title.

Suggestions coming from Giant Bomb API are trickier for me, since I'm using external API to get a list of objects, instead of entering my input data.

My Suggestion.java class looks like this:

package rest.library;


public class Suggestion {

    private long id;
    private String name;

    public Suggestion(){
    }

    public Suggestion(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}

In my Controller I want to do this:

@RequestMapping("/search")
public List<Suggestion> searchGames() { return gameService.searchGames(); }

Going under localhost:8080/search should return a List of Objects with search results gained from JSON request. It should look just like localhost:8080/games that returns me a list of games that I've sent using GET on Postman. I know that I get field "resource_type" from the API and there is no "id" field, but that's a problem for later since I think that filling selected class fields and adding id incrementaly won't be that much of a problem.

VapeKop
  • 349
  • 2
  • 4
  • 13
  • https://stackoverflow.com/questions/17037340/converting-jsonarray-to-arraylist – Harish Pathak Jul 13 '17 at 11:20
  • This is for ArrayList (I'm getting errors with incompatible types) and I don't know how to convert request (httpResponse to for e.g. JSONArray. – VapeKop Jul 13 '17 at 11:36
  • string to JsonArray https://stackoverflow.com/questions/15609306/convert-string-to-json-array – Harish Pathak Jul 13 '17 at 12:05
  • JSONObject myObject = new JSONObject(result); – Harish Pathak Jul 13 '17 at 12:06
  • https://stackoverflow.com/questions/18073849/get-a-json-object-from-a-http-response – Harish Pathak Jul 13 '17 at 12:07
  • Jackson can covert your response directly to your model, you can try that as well. – Harish Pathak Jul 13 '17 at 12:12
  • org.json.JSONException: JSONObject["results"] not found. I've tried first two links to do: JSONObject>JSONArray>ArrayLIST. org.json.JSONException: JSONObject["results"] not found. Something is off here: ` //JSONOBJECT>JSONARRAY JSONObject myObj = new JSONObject(request.getBody().getObject()); JSONArray jsonArray = myObj.getJSONArray("results"); ` – VapeKop Jul 13 '17 at 12:56

2 Answers2

1

What you need is a way to map the String object you received from your request into a HashMap, so that you can then set your object attributes, and form a list to return (even though there are APIs like Jackson which make implementing REST request processing logic much less painful).

This means first getting the InputStream from the HTTP request using response.getEntity().getContent(), and then creating a JSONParser as mentioned here.

This will enable you to get attributes from the JSON string as shown here.

In turn, this will enable you to use setter methods to create your own object list.

Let me know if that helped at all.

Austin Schaefer
  • 695
  • 5
  • 19
  • This is great, I will look into this ASAP. How easier would it be with Jackson? I mean, I tried but there were trouble as well. – VapeKop Jul 13 '17 at 13:27
  • I use Jackson at my workplace, and once it's set up, it's pretty easy. You create a resource method with a @GET annotation, a @Path(PATH_HERE) annotation, and add parameters (of any type) to the method which represent what the method body and/or path accept. That should be enough to automatically convert the JSON request body into the specified POJO. – Austin Schaefer Jul 13 '17 at 13:31
  • One more question regarding to your answer. Why request.getEntity().getContent() informs me that getEntity() cannot be resolved? – VapeKop Jul 13 '17 at 13:36
  • I'm unsure without seeing your current code. Create another question with your current code and I'll see if I can figure it out. – Austin Schaefer Jul 13 '17 at 13:41
  • Nevermind, it seems that getEntity has to be outside try method, but since I'm initializing inputStream AFTER request is initialized... It appears to be an unsolvable conflict. – VapeKop Jul 13 '17 at 13:43
  • It might be an option to have your method throw whatever exception types you need to catch, which will allow you to get rid of the try block. That, or you can just keep the one line inside the try block and put the rest outside. – Austin Schaefer Jul 13 '17 at 13:44
  • both of that doesn't work - if I try to catch the exception then getEntity() cannot be resolved again. if I try to keep InputStream outside, I have no 'request' initialized yet. It seems to be a full circle of error. I wouldn't have to deal with Hashmaps in case I decide to switch to Jackson, right? It seems to be the only rational way now for me, eh. – VapeKop Jul 13 '17 at 13:53
  • Correct, you would be dealing with your POJO instead of HashMaps. Just remember to have the incoming JSON string correctly formatted! (Also would recommend the @JsonIgnoreProperties(ignoreUnknown = true) annotation above your POJO class. This should prevent unknown input from ruining your day. – Austin Schaefer Jul 17 '17 at 07:51
  • 1
    The problem I had was also connected to my JSON response which was not enclosing {} brackets in my response if there were more than 10 results. I used a different external API with a more convenient JSON response and then mapping via Jackson worked like a charm. – VapeKop Jul 17 '17 at 09:21
0

I recomend use http-request built on apache http api. You can create class ResponseData to parse response.

 private static final HttpRequest<ResponseData> HTTP_REQUEST = 
        HttpRequestBuilder.createGet("http://giantbomb.com/api/search", ResponseData.class)
        .addDefaultHeader("Accept", "application/json")
        .addDefaultRequestParameter("api_key", "xxxxxxxxxxxxxxxxxxxxxxxxx")
        .addDefaultRequestParameter("format", "json")
        .addDefaultRequestParameter("resources", "game")
        .addDefaultRequestParameter("limit", "10")
        .addDefaultRequestParameter("field_list", "name")
        .addDefaultRequestParameter("query", "creed")
        .build();

  List<Suggestion> searchGames() {
      ResponseHandler<ResponseData> responseHandler = HTTP_REQUEST.execute();
      ResponseData responseData = responseHandler.get();

      // Here create the List<Suggestion> from responseData   

      return suggestions
  }

private class ResponseData{
    private String error;
    private int limit;
    private int offset;
    private int number_of_page_results;
    private int number_of_total_results;
    private int status_code;
    private List<Result> results;

    //getters and setters
}

private class Result{
    private String name;
    private String resource_type;

    //getters and setters
}
Beno
  • 945
  • 11
  • 22