135

I am trying to get response from the following Api :

https://api.github.com/users/username

But I don't know how to get response as String so that I can use the String to parse and get the JSONObject.

Retrofit version used:

retrofit:2.0.0-beta1

I have tried this until now:

public interface GitHubService {
        @GET("/users/{user}")
        public String listRepos(@Path("user") String user,Callback<String> callback);
    }

retrieving :

GitHubService service = retrofit.create(GitHubService.class);
        service.listRepos("username", new Callback<String>() {
            @Override
            public void onResponse(Response response) {
                System.out.println(response.toString());
            }

            @Override
            public void onFailure(Throwable t) {

            }
        });

exception:

Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for class java.lang.String. Tried:
    * retrofit.ExecutorCallAdapterFactory
            at retrofit.Utils.resolveCallAdapter(Utils.java:67)
            at retrofit.MethodHandler.createCallAdapter(MethodHandler.java:49)

Any help would be really appreciated.

RobinHood
  • 10,897
  • 4
  • 48
  • 97
Aakash
  • 5,181
  • 5
  • 20
  • 37
  • but for that i will have to use async task and as i have found out that retrofit is much faster than async task that is why i want to use retrofit, there must be some way to get either JSON or String or any method. I have searched a lot but didn't find anything. – Aakash Sep 16 '15 at 20:22
  • 1
    "i have found out that retrofit is much faster than async task " -- since Retrofit may well *use* `AsyncTask`, I suspect that your actual problem is in whatever you did for the HTTP requests when you made your comparison. – CommonsWare Sep 16 '15 at 20:27
  • http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/, i guess you know these facts pretty well but please tell me any way to achieve what i am trying to do. – Aakash Sep 16 '15 at 20:32
  • Alright thanks, but why does Twitter Fabric uses retrofit for making REST API calls, is that only their way to do it or is there any other reason behind it? – Aakash Sep 16 '15 at 20:43
  • 4
    "why does Twitter Fabric uses retrofit for making REST API calls" -- because Retrofit is great at making REST calls, when you want to actually have Retrofit parse the results. As I wrote, that is the *point* behind Retrofit, letting it handle the HTTP and parsing plumbing for you. You, for whatever reason, do not want Retrofit doing the parsing. That is fine, but that is not what Retrofit is for. Square's library for ordinary HTTP operations is OkHttp (Retrotfit will even use OkHttp if you have it in your app). – CommonsWare Sep 16 '15 at 20:47
  • Thank you so much, you made the whole point clear to me, in my case then it is better to use HttpUrlConnection then. – Aakash Sep 16 '15 at 20:51
  • @CommonsWare for the most part I agree but you know; working on real world APIs where most of the time it returns JSON but maybe sometimes (some bad backend coders) it's returning just a String or an iCal feed on some endpoints. – Oliver Dixon Feb 28 '17 at 08:26
  • @CommonsWare the point behind Retrofit is not to parse json but to provide elegant interface for a backend API. And sometimes cases where we need to parse a raw string occur - take the Bitbucket API for example and this endpoint: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Busername%7D/%7Brepo_slug%7D/diff/%7Bspec%7D – Michał Klimczak Oct 02 '17 at 18:43

1 Answers1

262

** Update ** A scalars converter has been added to retrofit that allows for a String response with less ceremony than my original answer below.

Example interface --

public interface GitHubService {
    @GET("/users/{user}")
    Call<String> listRepos(@Path("user") String user);
}

Add the ScalarsConverterFactory to your retrofit builder. Note: If using ScalarsConverterFactory and another factory, add the scalars factory first.

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(ScalarsConverterFactory.create())
    // add other factories here, if needed.
    .build();

You will also need to include the scalars converter in your gradle file --

implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'

--- Original Answer (still works, just more code) ---

I agree with @CommonsWare that it seems a bit odd that you want to intercept the request to process the JSON yourself. Most of the time the POJO has all the data you need, so no need to mess around in JSONObject land. I suspect your specific problem might be better solved using a custom gson TypeAdapter or a retrofit Converter if you need to manipulate the JSON. However, retrofit provides more the just JSON parsing via Gson. It also manages a lot of the other tedious tasks involved in REST requests. Just because you don't want to use one of the features, doesn't mean you have to throw the whole thing out. There are times you just want to get the raw stream, so here is how to do it -

First, if you are using Retrofit 2, you should start using the Call API. Instead of sending an object to convert as the type parameter, use ResponseBody from okhttp --

public interface GitHubService {
    @GET("/users/{user}")
    Call<ResponseBody> listRepos(@Path("user") String user);
}

then you can create and execute your call --

GitHubService service = retrofit.create(GitHubService.class);
Call<ResponseBody> result = service.listRepos(username);
result.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Response<ResponseBody> response) {
        try {
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(Throwable t) {
        e.printStackTrace();
    }
});

Note The code above calls string() on the response object, which reads the entire response into a String. If you are passing the body off to something that can ingest streams, you can call charStream() instead. See the ResponseBody docs.

Mark O'Sullivan
  • 10,138
  • 6
  • 39
  • 60
iagreen
  • 31,470
  • 8
  • 76
  • 90
  • Could you please print the stack trace in case of failure? I know it's not the focus of this question, but someone unexperienced might copy and paste this code. – Hosam Aly Oct 18 '15 at 20:27
  • For those who just want to get the response to string, you can convert the response.body() to string use this: private void logJsonPayload(Object object){ //Log JSON String try { ObjectWriter ow = new ObjectMapper().writer(); String jsonPayload = ow.writeValueAsString(object); Log.d("!!!", "JSON Payload: " + jsonPayload); } catch (JsonProcessingException e) { e.printStackTrace(); } } – Kim Montano May 14 '16 at 13:00
  • 1
    in my Retrofit the callback different : public void onResponse(Call call, Response response) { in this response there is not method string() – Michael Aug 21 '16 at 05:29
  • .string() changes "/url" this to "\/url" this – Jemshit Sep 20 '16 at 12:09
  • 5
    Make sure to use `okhttp3.ResponseBody` when using Retrofit 2 and not `com.squareup.okhttp.ResponseBody` which would throw the same error as described in the question. – ubuntudroid Oct 12 '16 at 20:04
  • Thanks man `System.out.println(response.body().string());` this is what I need.. – Shailendra Madda Mar 31 '17 at 14:33
  • you need to return 'String' only, not 'Call' otherwise you will get "Unable to create converter for retrofit2.Call " – Win Myo Htet Aug 14 '22 at 09:35
  • `t.printStackTrace()` thank me later – Iglesias Leonardo Jan 30 '23 at 21:49