Retrofit callback get response body - android

I am testing Retrofit to compare it with Volley and I am struggling to get the response from my requests. For example, I do something like this:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://localhost:8080")
.build();
MyService service = restAdapter.create(MyService.class);
service.getToto("toto", new Callback<Toto>() {
#Override
public void success(Toto toto, Response response) {
// Try to get response body
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
try {
reader = new BufferedReader(
new InputStreamReader(response.getBody().in()));
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
String result = sb.toString();
}
#Override
public void failure(RetrofitError error) {}
});
It works, the object toto is set, but for testing purposes, I also want to display the JSON response returned by the server.
So I am trying to read the InputStream from response.getBody() which is a TypedInputStream.
Unfortunately, I always get an IOException : Stream is closed.
I tried to use the Utils class from Retrofit but I get the same IOException error.

Inside callback's angle brackets write "Response" and then extract the stream from this response.
service.getToto("toto", new Callback<Response>() {
#Override
public void success(Response result, Response response) {
//Try to get response body
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(result.getBody().in()));
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
String result = sb.toString();
}
#Override
public void failure(RetrofitError error) {
}
});

Before Retrofit 2.0
String bodyString = new String(((TypedByteArray) response.getBody()).getBytes());
Retrofit 2.0
String bodyString = new String(response.body().bytes());

If you set .setLogLevel(RestAdapter.LogLevel.FULL) on the RestAdapter that you use to create the service you should get the raw JSON response output in the debug console.
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("http://my_lovely_api.com")
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
mService = restAdapter.create(MyService.class);
If you want to do something different with this raw response you can still use the code you have in your success block to create a JSON string assuming that you keep the LogLevel.FULL in the setLogLevel method, if not then it won't parse the InputStream from response.getBody().in() as it's already been read and closed.

I recently encountered a similar problem. I wanted to look at some json in the response body but didn't want to deal with the TypedByteArray from Retrofit. I found the quickest way to get around it was to make a Pojo(Plain Old Java Object) with a single String field. More Generally you would make a Pojo with one field corresponding to whatever data you wanted to look at.
For example, say I was making a request in which the response from the server was a single string in the response's body called "access_token"
My Pojo would look like this:
public class AccessToken{
String accessToken;
public AccessToken() {}
public String getAccessToken() {
return accessToken;
}
}
and then my callback would look like this
Callback<AccessToken> callback = new Callback<AccessToken>() {
#Override
public void success(AccessToken accessToken, Response response) {
Log.d(TAG,"access token: "+ accessToken.getAccessToken());
}
#Override
public void failure(RetrofitError error) {
Log.E(TAG,"error: "+ error.toString());
}
};
This will enable you to look at what you received in the response.

Please, don't use streams and straemReaders for this.
Use smart solutions like square does:
private Response logAndReplaceResponse(String url, Response response, long elapsedTime)
http://www.programcreek.com/java-api-examples/index.php?source_dir=retrofit-jaxrs-master/retrofit/src/main/java/retrofit/RestAdapter.java
example:
private String getResponseBody(Response response) {
String result = "";
//Try to get response body
if (response.getBody() instanceof TypedByteArray) {
TypedByteArray b = (TypedByteArray) response.getBody();
result = new String(b.getBytes());
}
return result;
}

Another solution would be to do something like the following:
private static String bodyAsString(RequestBody body) {
try {
Buffer buffer = new Buffer();
body.writeTo(buffer);
return buffer.readString(body.contentType().charset());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Taken from https://github.com/square/okhttp/blob/master/okcurl/src/test/java/com/squareup/okhttp/curl/MainTest.java#L93-L101

With version 2.1.0, you can get the content as
public void onResponse(Call<T> call, Response<T> response) {
String errorString = response.errorBody().string();
}

Just do it like this:
ModelClass modelclass=response.response.body()
System.out.println("****************-----retro rsp----1-------"+modelclass.getMessage());

in your model of response press cmd+n and override "toString" method and only call as response.toString();
#Override
public String toString() {
return "{" +
"key_one='" + var_keyone + '\'' +
", key_two='" + var_keytwo + '\'' +
'}';
}

Related

How to post oauth API for login using Retrofit 1.9.0 in Android

I have done successfully registration using below API but I'm not able to login
got error message from server Retrofit:
{"code":401,"message":"Authentication failed","error":{"reason":"authError"}
This is my interface:
public static final String BASE_URL= "http://ashwinku.fwd.wf/ssng-project/api";
public static final String REGISTER_OPERATION = "/registerUser";
public static final String LOGIN_OPERATION = "/loginUser";
This is my User(Bean) Class for login:
public User(String firstName, String password) {
this.firstName=firstName;
this.password = password;
}
This is my Login fragment:
private void loginuser(String firstName, String password) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.BASE_URL)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
//Creating object for our interface
RequestInterface api = restAdapter.create(RequestInterface.class);
user = new User(firstName,password);
user.setFirstName(firstName);
user.setPassword(password);
//Defining the method insertuser of our interface
api.loginuser(user, new Callback<User>() {
#Override
public void success(User result, Response response) {
BufferedReader reader = null;
//An string to store output from the server
String output = "";
try {
//Initializing buffered reader
reader = new BufferedReader(new InputStreamReader(response.getBody().in()));
//Reading the output in the string
output = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
//Displaying the output as a toast
Toast.makeText(getActivity(), output, Toast.LENGTH_LONG).show();
}
#Override
public void failure(RetrofitError error) {
Toast.makeText(getActivity(), error.toString(), Toast.LENGTH_LONG).show();
}
});
}
I using 1.9.0 retrofit but not able to login. Please help. It gives me error.
Try this out
api.loginuser(user, new Callback<User>() {
#Override
public void success(User result, Response response) {
//Try to get response body
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(result.getBody().in()));
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
String result = sb.toString();
Toast.makeText(getActivity(), result, Toast.LENGTH_LONG).show();
}
#Override
public void failure(RetrofitError error) {
Toast.makeText(getActivity(), error.toString(), Toast.LENGTH_LONG).show();
}
});
Also i just noticed that you are getting 401 error code, which means - Unauthorized: Access is denied due to invalid credentials
So that could be the problem too, you need to fix that on your side.
hope it helps

Retrofit - POST request with #Path and without parameters

The request to API as follows:
POST /verify/phone/{userid}/
Mandatory parameters: userid (integer)
Return: nothing
I receive Bad Request error all the time if I want to verify user with id 1 (for example):
Response{protocol=http/1.1, code=400, message=Bad Request, url=http://dummyapi.com/verify/phone/1/}
Posting the same request using Postman works well.
Code:
#POST("/verify/phone/{userid}/")
Call<String> postVerifyPhone(#Path("userid") int userId);
public void postVerifyPhone(int userID){
showProgressBar();
RestClient.GitApiInterface service = RestClient.getClient();
Call<String> call = service.postVerifyPhone(userID);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
hideProgressBar();
if (response.isSuccess()) {
String result = response.body();
} else {
Log.d("Fail: ", response.body()); //everytime here with Bad Request
}
}
#Override
public void onFailure(Throwable t) {
hideProgressBar();
}
});
}
I'm using String as the return type since there's message returned when there're no user with requested ID in db.
What could be a cause?
I am calling below code for reading response data.
public void postVerifyPhone(int userID){
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(Constants.URL).build();
RetrofitApi retrofitApi = restAdapter.create(RetrofitApi.class);
retrofitApi.postVerifyPhone(userID, new Callback<Response>() {
#Override
public void success(Response response, Response response2) {
BufferedReader reader = null;
StringBuilder sb = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(response.getBody().in()));
String line;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
String result = sb.toString();
// System.out.println("res:" + result.toString());
}
#Override
public void failure(RetrofitError error) {
hidePDialog();
}
});
}
below is postVerifyPhone() code
#FormUrlEncoded
#POST("/verify/phone/")
public void postVerifyPhone(#Field("userID") String userID, Callback<Response> resonse);
It is working fine for me.please check it once.
I think the right annotation is #PathParam, not #Path

Logical error in getting a text from URL with okHttp

Im trying to write an app to read a text file from an url like this "http://chemvaaj.xzn.ir/test/words.txt"
it seems right but it doesn't return what it should :\
here's my code :
public String DL (){
OkHttpHandler handler = new OkHttpHandler();
String text ="";
try {
text = handler.execute().get();
if (text!= null && text.length()> 0){
System.out.println("not empty");
return text;
}
} catch (Exception e) {
text= "empty !!";
}
return text;
}
and here is OkHttpHandler class :
public class OkHttpHandler extends AsyncTask<Void, Void, String> {
private final String DB_URL = "http://chemvaaj.xzn.ir/test/words.txt";
OkHttpClient httpClient = new OkHttpClient();
#Override
protected String doInBackground(Void... params) {
Request.Builder builder = new Request.Builder();
builder.url(DB_URL);
Request request = builder.build();
try {
Response response = httpClient.newCall(request).execute();
return response.body().toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.e("ANSWER", "" + s);
}
}
and here's my logcat after call DL() function :
10-28 00:23:25.167 17288-17288/erfan.bagheri.chemvaaj E/ANSWER﹕ com.squareup.okhttp.internal.http.RealResponseBody#423bc6b8
You should replace return response.body().toString(); by return response.body().string();
Please refer to my following working sample code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
new GetFileRequest().execute();
}
...
private class GetFileRequest extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://chemvaaj.xzn.ir/test/words.txt")
.build();
Response response = client.newCall(request).execute();
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
return e.toString();
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (mTextView != null && result != null) {
mTextView.setText(result);
}
}
}
Here is the screenshot
Hope this helps!
First of all, please check how an AsyncTask works. Here's the official, easy to understand how-to-use.
Then you'll find that the method execute() returns the task itself, not the resulting String object.
It seems that OkHttpClient's returned Response object can be transformed to string in the following way:
response.body().toString();
Just one more hint: please avoid returning null in any method, it's considered very bad practice.
OkHttpClient is used in the wrong way(Suppose you want to use async). OkHttp is a full featured Http client library and has Asynchronous requests implemented in itself.
So there is no need to Android AsyncTask.
Here is the right way:
private final OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://chemvaaj.xzn.ir/test/words.txt")
.build();
client.newCall(request).enqueue(new Callback() {
#Override public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
#Override public void onFailure(Request request, Throwable throwable) {
throwable.printStackTrace();
}
});
I am not familiar with OkHttpClient but from the log I am guessing that the body response is a complex object that does not have a toString() that will show you a human readable response. You will probably have to print a specific member of that object to get your readable response.
try this
OkHttpClient and callback:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// Headers responseHeaders = response.headers();
// for (int i = 0; i < responseHeaders.size(); i++) {
// System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
// }
// System.out.println(response.body().string());
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
}
});

Retrofit: Sending POST request to server in android

I am using Retrofit to call APIs. I am sending a post request to API but in the callback I am getting empty JSON like this {}.
Below is the code for RetrofitService
#POST("/com/searchusers.php")
void getUser(#Body JSONObject searchstring, Callback<JSONObject> callBack);
where searchstring JSON is like this {"search":"nitesh"}. In response I am supposed to get the detail of user "nitesh".
Below is the code for sending POST request
RetrofitService mRetrofitService = app.getRetrofitService();
mRetrofitService.getUser(user, new Callback<JSONObject>() {
#Override
public void success(JSONObject result, Response arg1) {
System.out.println("success, result: " + result);
}
#Override
public void failure(RetrofitError error) {
System.out.println("failure, error: " + error);
}
});
I am getting this output
success, result: {}
Expected output is
success, result: {"name":"nitesh",....rest of the details}
Edit:
I tried using Response instead of JSONObject like this CallBack<Response> and then I converted the raw response into String and I got the expected result. But the problem is its in String, I want the response in JSONObject.
How can I get the exact result using CallBack<JSONObject> ...?
After waiting for the best response I thought of answering my own question. This is how I resolved my problem.
I changed the converter of RestAdapter of RetrofitService and created my own Converter. Below is my StringConverter
static class StringConverter implements Converter {
#Override
public Object fromBody(TypedInput typedInput, Type type) throws ConversionException {
String text = null;
try {
text = fromStream(typedInput.in());
} catch (IOException ignored) {/*NOP*/ }
return text;
}
#Override
public TypedOutput toBody(Object o) {
return null;
}
public static String fromStream(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String newLine = System.getProperty("line.separator");
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(newLine);
}
return out.toString();
}
}
Then I set this converter to the RestAdapter in the Application class.
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.setConverter(new StringConverter())
.build();
mRetrofitService = restAdapter.create(RetrofitService.class);
Now whenever I use Retrofit, I get the response in String. Then I converted that String JSONObject.
RetrofitService mRetrofitService = app.getRetrofitService();
mRetrofitService.getUser(user, new Callback<String>() {
#Override
public void success(String result, Response arg1) {
System.out.println("success, result: " + result);
JSONObject jsonObject = new JSONObject(result);
}
#Override
public void failure(RetrofitError error) {
System.out.println("failure, error: " + error);
}
});
Hence, I got the result in JSON form. Then I parsed this JSON as required.
it may help you
JSONObject responseJsonObj = new JSONObject(responseString);

How can I return String or JSONObject from asynchronous callback using Retrofit?

For example, calling
api.getUserName(userId, new Callback<String>() {...});
cause:
retrofit.RetrofitError: retrofit.converter.ConversionException:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
Expected a string but was BEGIN_OBJECT at line 1 column 2
I think I must disable gson parsing into POJOs but can't figure out how to do it.
I figured it out. It's embarrassing but it was very simple... Temporary solution may be like this:
public void success(Response response, Response ignored) {
TypedInput body = response.getBody();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(body.in()));
StringBuilder out = new StringBuilder();
String newLine = System.getProperty("line.separator");
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(newLine);
}
// Prints the correct String representation of body.
System.out.println(out);
} catch (IOException e) {
e.printStackTrace();
}
}
But if you want to get directly Callback the Better way is to use Converter.
public class Main {
public interface ApiService {
#GET("/api/")
public void getJson(Callback<String> callback);
}
public static void main(String[] args) {
RestAdapter restAdapter = new RestAdapter.Builder()
.setClient(new MockClient())
.setConverter(new StringConverter())
.setEndpoint("http://www.example.com").build();
ApiService service = restAdapter.create(ApiService.class);
service.getJson(new Callback<String>() {
#Override
public void success(String str, Response ignored) {
// Prints the correct String representation of body.
System.out.println(str);
}
#Override
public void failure(RetrofitError retrofitError) {
System.out.println("Failure, retrofitError" + retrofitError);
}
});
}
static class StringConverter implements Converter {
#Override
public Object fromBody(TypedInput typedInput, Type type) throws ConversionException {
String text = null;
try {
text = fromStream(typedInput.in());
} catch (IOException ignored) {/*NOP*/ }
return text;
}
#Override
public TypedOutput toBody(Object o) {
return null;
}
public static String fromStream(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String newLine = System.getProperty("line.separator");
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(newLine);
}
return out.toString();
}
}
public static class MockClient implements Client {
#Override
public Response execute(Request request) throws IOException {
URI uri = URI.create(request.getUrl());
String responseString = "";
if (uri.getPath().equals("/api/")) {
responseString = "{result:\"ok\"}";
} else {
responseString = "{result:\"error\"}";
}
return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST,
new TypedByteArray("application/json", responseString.getBytes()));
}
}
}
If you know how to improve this code - please feel free to write about it.
A possible solution would be to use JsonElement as the Callback type (Callback<JsonElement>). In your original example:
api.getUserName(userId, new Callback<JsonElement>() {...});
In the success method you can convert the JsonElement to either a String or a JsonObject.
JsonObject jsonObj = element.getAsJsonObject();
String strObj = element.toString();
Retrofit 2.0.0-beta3 adds a converter-scalars module provides a
Converter.Factory for converting String, the 8 primitive types,
and the 8 boxed primitive types as text/plain bodies. Install this
before your normal converter to avoid passing these simple scalars
through, for example, a JSON converter.
So, first add converter-scalars module to build.gradle file for your application.
dependencies {
...
// use your Retrofit version (requires at minimum 2.0.0-beta3) instead of 2.0.0
// also do not forget to add other Retrofit module you needed
compile 'com.squareup.retrofit2:converter-scalars:2.0.0'
}
Then, create your Retrofit instance like this:
new Retrofit.Builder()
.baseUrl(BASE_URL)
// add the converter-scalars for coverting String
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
.create(Service.class);
Now you can use API declaration like this:
interface Service {
#GET("/users/{id}/name")
Call<String> userName(#Path("userId") String userId);
// RxJava version
#GET("/users/{id}/name")
Observable<String> userName(#Path("userId") String userId);
}
The answer may be much shorter than already mentioned and doesn't require any additional libraries:
In declaration use Response as follows:
... Callback<Response> callback);
And while handling response:
#Override
public void success(Response s, Response response) {
new JSONObject(new String(((TypedByteArray) response.getBody()).getBytes()))
}
When #lordmegamax answer completely work there is much nicer solution which is come from
Okio is a new library that complements java.io and java.nio
other squares project which already tight with retrofit and therefore you don't need to add any new dependency and it's have to be reliable:
ByteString.read(body.in(), (int) body.length()).utf8();
ByteString is an immutable sequence of bytes. For character data, String is fundamental. ByteString is String's long-lost brother, making it easy to treat binary data as a value. This class is ergonomic: it knows how to encode and decode itself as hex, base64, and UTF-8.
Full example:
public class StringConverter implements Converter {
#Override public Object fromBody(TypedInput body, Type type) throws ConversionException {
try {
return ByteString.read(body.in(), (int) body.length()).utf8();
} catch (IOException e) {
throw new ConversionException("Problem when convert string", e);
}
}
#Override public TypedOutput toBody(Object object) {
return new TypedString((String) object);
}
}
To get Call JSONObject or JSONArray
you can create custom factory or copy it from here : https://github.com/marcinOz/Retrofit2JSONConverterFactory

Categories

Resources