Getting simple JSON object response using Retrofit library - android

I have a web query with JSON response as:
{
"status":true,
"result":
{
"id":"1",
"name":"ABC 1",
"email":"info#ABc.dcom",
"password":"123456",
"status":false,
"created":"0000-00-00 00:00:00"
},
"message":"Login successfully"
}
I am using the following code for:
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<JSONObject> callback);
In Debugger the query made by the Retrofit library is correct, however I get an empty JSON in response.
ApiManager.getInstance().mUrlManager.login(
email.getText().toString().trim(),
password.getText().toString().trim(),
new Callback<JSONObject>()
{
#Override
public void success(JSONObject jsonObj, Response response)
{
mDialog.dismiss();

Simply use JsonElement insted of JSONobject. Like:
#GET("/stockers/login")
Call<JsonElement> getLogin(
#Query("email") String email,
#Query("password") String password
);

The answers seam kinda old and for Retrofit 1, if you are using Retrofit 2 and don't want to use a converter you have to use ResponseBody.
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<ResponseBody> callback);
And then in your callback in the onResponse method call string on the body and create a JSONObject from it.
if(response.isSuccessful())
JSONObject json = new JSONObject(response.body().string());

Instead of Callback with JSONObject class, you could use the Retrofit basic callback which use the Response class and then, once you get the response, you had to create the JSONObject from it.
See this:
https://stackoverflow.com/a/30870326/2037304
Otherwise you can create your own model class to handle the response.
First the Result class:
public class Result {
public int id;
public String name;
public String email;
public String password;
public boolean status;
public Date created;
}
And then your response class to use with Retrofit
public class MyResponse {
public boolean status;
public Result result;
public String message;
}
Now you can call:
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<MyResponse> callback);

You can create custom factory like belowe or copy it from here :
https://github.com/marcinOz/Retrofit2JSONConverterFactory
public class JSONConverterFactory extends Converter.Factory {
public static JSONConverterFactory create() {
return new JSONConverterFactory();
}
private JSONConverterFactory() {
}
#Override public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (type == JSONObject.class
|| type == JSONArray.class) {
return JSONRequestBodyConverter.INSTANCE;
}
return null;
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == JSONObject.class) {
return JSONResponseBodyConverters.JSONObjectResponseBodyConverter.INSTANCE;
}
if (type == JSONArray.class) {
return JSONResponseBodyConverters.JSONArrayResponseBodyConverter.INSTANCE;
}
return null;
}
}
public class JSONRequestBodyConverter<T> implements Converter<T, RequestBody> {
static final JSONRequestBodyConverter<Object> INSTANCE = new JSONRequestBodyConverter<>();
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain; charset=UTF-8");
private JSONRequestBodyConverter() {
}
#Override public RequestBody convert(T value) throws IOException {
return RequestBody.create(MEDIA_TYPE, String.valueOf(value));
}
}
public class JSONResponseBodyConverters {
private JSONResponseBodyConverters() {}
static final class JSONObjectResponseBodyConverter implements Converter<ResponseBody, JSONObject> {
static final JSONObjectResponseBodyConverter INSTANCE = new JSONObjectResponseBodyConverter();
#Override public JSONObject convert(ResponseBody value) throws IOException {
try {
return new JSONObject(value.string());
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
static final class JSONArrayResponseBodyConverter implements Converter<ResponseBody, JSONArray> {
static final JSONArrayResponseBodyConverter INSTANCE = new JSONArrayResponseBodyConverter();
#Override public JSONArray convert(ResponseBody value) throws IOException {
try {
return new JSONArray(value.string());
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
}
}

try this instead :
#GET("/stockers/login")
public void login(
#Query("email") String email,
#Query("password") String password,
Callback<Response> callback); // set the callback generic parameter to Response
ApiManager.getInstance().mUrlManager.login(
email.getText().toString().trim(),
password.getText().toString().trim(),
new Callback<Response>()
{
#Override
public void success(Response response, Response response1)
{
String json = response.getBody();
try {
JSONObject jsonObj = new JSONObject(json);
} catch(JSONException e) {
}
alog.dismiss();

Just define the type of the object you want to get as a String as com.google.gson.JsonObject instead of String and call .toString() on that object to get the JSON string itself.

I`m using this site to create my classes (POJO) from JSON.
http://www.jsonschema2pojo.org/
just be sure to set to JSON insted of JSON Schema and check GSON, because retrofit is using GSON as well for parsing.
your retrofit code looks fine.

Use JacksonConverterFactory instead of GsonConverterFactory while setting up Retrofit. Now you can directly work with JsonObject responses.
compile 'com.squareup.retrofit2:converter-jackson:2.1.0'

Related

How to convert retrofit response into json object

I just wanted to know that how could I convert this retrofit library response which is actually a JSON response to JSON object so I could use this in my android app to do something because I can not do anything with response in the buffered reader.
public void getMe(){
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ROOT_URL)
.build();
myApi api = adapter.create(myApi.class);
api.sendme(
userEmail,
rs,
Team1,
Team2,
new retrofit.Callback<retrofit.client.Response>() {
#Override
public void success(retrofit.client.Response result, retrofit.client.Response response) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(result.getBody().in()));
if (!output.equals("")) {
output = reader.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void failure(RetrofitError error) {
// loading.dismiss();
Toast.makeText(Leaderboard.this, "", Toast.LENGTH_LONG).show();
}
}
);
}
here get me is sending post response to the server
public interface myApi {
#FormUrlEncoded
#POST("/myleaderboard.php")
void sendme(
#Field("userEmail") String userEmail,
#Field("rs") String rs,
#Field("team1") String team1,
#Field("team2") String team2,
Callback<Response> callback);
}
I m getting JSON response and I have to store that in my android code somehow whether that be using JSON object or anything else if possible.
please help me with this
Just change the myAPi code to
public interface myApi {
#FormUrlEncoded
#POST("/myleaderboard.php")
void sendme(
#Field("userEmail") String userEmail,
#Field("rs") String rs,
#Field("team1") String team1,
#Field("team2") String team2,
Callback<JsonObject> callback);
}
it will return JsonObject directly
Use GsonConverterFactory to convert incoming json into model/pojo class
implementation 'com.squareup.retrofit2:converter-gson:LATEST_VERSION'
Please go through following links
Retrofit Library Tutorial
Consuming-APIs-with-Retrofit
Use this link to convert your JSON into POJO with select options as selected in image below [http://www.jsonschema2pojo.org/
You will get a POJO class for your response like this
public class Result {
#SerializedName("id")
#Expose
private Integer id;
/**
*
* #return
* The id
*/
public Integer getId() {
return id;
}
/**
*
* #param id
* The id
*/
public void setId(Integer id) {
this.id = id;
}
then and use interface like this:
#FormUrlEncoded
#POST("/api/level")
Call<Result> checkLevel(#Field("id") int id);
add the dependencies
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.+'
and call like this:
Call<Result> call = api.checkLevel(1);
call.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
response.body(); // have your all data
int id =response.body().getId();
String userName = response.body().getUsername();
String level = response.body().getLevel();
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
}
});
to get the response in JSON don't use addConverterFactory(GsonConverterFactory.create()) from Retrofit.

Why response.body() its null?

Im using retrofit to send a a json object to the server, im trying to create a user, im sending this json object
{"apellido":"prueba","email":"prueba#hotmail.com","fechaDeNacimiento":"11/29/1998","formaDeRegistro":"Android","nombre":"prueba","password":"12345678","username":"prueba"}
In this example i create a invalid user , so the server response with a json object where code its the code error and message its the explication of the error
[{"code":"5","message":"The email is in use"}]
Interface
public interface UserClient {
#POST("usuarios")
Call<Usuarios> create(#Body Usuarios usuario);
}
Data model
import com.google.gson.annotations.SerializedName;
public class Usuarios {
#SerializedName("username")
String username;
#SerializedName("email")
String email;
#SerializedName("password")
String password;
#SerializedName("nombre")
String nombre;
#SerializedName("apellido")
String apellido;
#SerializedName("fechaDeNacimiento")
String fechaDeNacimiento;
#SerializedName("formaDeRegistro")
String formaDeRegistro;
String message;
public Usuarios(String email, String username, String password, String nombre, String apellido, String fechaDeNacimiento, String formaDeRegistro){
this.username=username;
this.email=email;
this.password=password;
this.nombre = nombre;
this.apellido= apellido;
this.fechaDeNacimiento = fechaDeNacimiento;
this.formaDeRegistro = formaDeRegistro;
}
public String getMessage(){
return message;
}
}
and Retrofit implement
OkHttpClient.Builder okhttpClientBuilder=new OkHttpClient.Builder();
HttpLoggingInterceptor loggin=new HttpLoggingInterceptor();
loggin.setLevel(HttpLoggingInterceptor.Level.BODY);
okhttpClientBuilder.addInterceptor(loggin);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("https://intense-lake-39874.herokuapp.com")
.addConverterFactory(GsonConverterFactory.create())
.client(okhttpClientBuilder.build());
Retrofit retrofit = builder.build();
UserClient service = retrofit.create(UserClient.class);
Call<Usuarios> call = service.create(usuario);
call.enqueue(new Callback<Usuarios>() {
#Override
public void onResponse(Call<Usuarios> call, Response<Usuarios> response) {
Toast.makeText(Main2Activity.this,"Usuario Registrado! "+response.body().getMessage,Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<Usuarios> call, Throwable t) {
Toast.makeText(Main2Activity.this,"Algo fallo..",Toast.LENGTH_SHORT).show();
}
});
}
So i can see the logcat response but in the body its appoint to null, how i can acces to the "message"?
This is the logcat
That error is because your response is not successful therefore you need to parse the error body, try with this code:
if (response.isSuccessful()) {
// Do your success stuff...
} else
{
try
{
JSONObject jObjError = new JSONObject(response.errorBody().string());
Toast.makeText(getContext(), jObjError.getString("message"), Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
Of course that you can use another parser like Gson .

How to post long JSON as a body using retrofit?

I am using retrofit to handle the API calls but facing problem while posting long JSON. I am getting:
internal server error(code : 500)
I need to convert post params to below format.
Body :
{"UserId" : "2",
"PortalId" : "1",
"LocaleId" : "1",
"CatalogId" : "3",
"Items" : [{"Name" : "ap1234","Quantity" : "1"}]}
Below is the code I am using
Api Call :
JSONArray array = new JSONArray();
try {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("Name", "ap1234");
jsonObject1.put("Quantity", "1");
array.put(jsonObject1);
} catch (JSONException e) {
e.printStackTrace();
}
Call data = mApiInterface.getData("application/json","2", "1", "1", "3", array.toString());
addToCart.enqueue(new Callback<DataResponse>() {
Retrofit Interface :
#FormUrlEncoded
#POST(API_ADD_TO_CART)
Call<DataResponse> getData(#Header("Content-Type") String contentType, #Field("UserId") String userId,
#Field("LocaleId") String localeId,
#Field("PortalId") String portalId,
#Field("CatalogId") String CatalogId,
#Field("Items") String Items);
#Body String body has to be used.
JSONArray array = new JSONArray();
try {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("Name", "ap1234");
jsonObject1.put("Quantity", "1");
/*
create a json object pass as body
{"UserId" : "2",
"PortalId" : "1",
"LocaleId" : "1",
"CatalogId" : "3",
"Items" : [{"Name" : "ap1234","Quantity" : "1"}]}
*/
array.put(jsonObject1);
} catch (JSONException e) {
e.printStackTrace();
}
Call data = mApiInterface.getData("application/json","2", "1", "1",
"3", array.toString());
addToCart.enqueue(new Callback<DataResponse>() {
change as following
#FormUrlEncoded
#POST(API_ADD_TO_CART)
Call<DataResponse> getData(#Header("Content-Type") String contentType, #Body String body);
Try using the #Body annotation .
Create a User class add your data to that instance and with retrofit instead of using #field you should send #Body with the User class as body .
example:
interface Foo {
#POST("/jayson")
FooResponse postRawJson(#Body TypedInput body);
}
For more info I found this link to be helpful
https://futurestud.io/tutorials/retrofit-send-objects-in-request-body
retrofit is too typical to implement and this is the easiest method I ever used for retrofit.
public void sendPost(String s1) {
dialog.setMessage("Please wait...");
dialog.setCancelable(false);
dialog.show();
apiService.getData(s1).enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
dialog.dismiss();
try {
if (response != null) {
JSONObject jsonObject = new JSONObject(response.body().toString());
String status = jsonObject.optString("status");
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
if (dialog != null) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
});
}
I don't think #Header("Content-Type") String contentType is useful in api services, just use #Field to send request
#POST("list_data")
#FormUrlEncoded
Call<JsonObject> shopList(#Field("string") String string);
Thanks for the help guys I did it using #Body
#POST(API_ADD_TO_CART)
Call<ShoppingCartResponse> getData(#Header("Content-Type") String contentType, #Body DataRequest request)
public class AddToCartRequest {
#SerializedName("UserId")
#Expose
private String userId;
#SerializedName("PortalId")
#Expose
private String portalId;
#SerializedName("LocaleId")
#Expose
private String localeId;
#SerializedName("CatalogId")
#Expose
private String catalogId;
#SerializedName("Items")
#Expose
private List<Items> items = null;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPortalId() {
return portalId;
}
public void setPortalId(String portalId) {
this.portalId = portalId;
}
public String getLocaleId() {
return localeId;
}
public void setLocaleId(String localeId) {
this.localeId = localeId;
}
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}

Simple login form with Retrofit

I'm starting to work with Retrofit but I'm stuck on this simple step. I have a login form and I'm trying to authenticate with the server but I just can't send the request.
This is what I've tried:
My Retrofit client:
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
My login interface:
public interface Login {
#POST(LOGIN)
Call<String> loginWithCredentials(#Body LoginCredentials data);
}
The LoginCredentials class:
public class LoginCredentials {
private String name;
private String pass;
public LoginCredentials(String name, String pass) {
this.name = name;
this.pass = pass;
}
}
And the part where I call it:
#Override
public void onClick(View v) {
showProgress(true);
String username = userField.getText().toString();
String password = passField.getText().toString();
ApiController.Login loginClient = ApiController.createService(ApiController.Login.class);
Call<String> call =loginClient.loginWithCredentials(new LoginCredentials(username, password));
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
handleResponse(response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
showProgress(false);
Log.e(TAG, t.getLocalizedMessage());
}
});
}
And I keep getting the error Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $but I have no idea what it means.
I figured it out. It was easier than I thought. You can skip the parsing that Retrofit does by setting the response type of the method as ResponseBody. Them you just need to read the response and use the string() method that provides. That's it!
Example:
public interface Login {
#POST(LOGIN)
Call<ResponseBody> loginWithCredentials(#Body LoginCredentials data);
}
Then use like this:
String username = userField.getText().toString();
String password = passField.getText().toString();
ApiController.Login loginClient = ApiController.createService(ApiController.Login.class);
Call<ResponseBody> call = loginClient.loginWithCredentials(new LoginCredentials(username, password));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
// get String from response
String stringResponse = response.body().string();
// Do whatever you want with the String
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// handle error
}
});
This error means that gson trying to parse string from server as JSON object and can't find the opening bracket.
I think you could return actual JSON from server like
{"api_token": "token"}
Also this bug could possibly be solved by importing latest GSON version mentioned here

Extracting JSON data with Retrofit and Gson

I'm trying to figure out how to extract data from my JSON response and loop through the data. I have the following Retrofit code to request the JSON data from my REST API:
final RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(URL)
.build();
final ApiEndpointInterface apiService = restAdapter.create(ApiEndpointInterface.class);
apiService.getJsonData(1, new Callback<User>() {
#Override
public void success(User user, Response response) {
Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new Deserializer()).create();
User c = gson.fromJson(response.getBody().toString(), User.class);
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
}
});
And my deserializer:
class Deserializer implements JsonDeserializer<User> {
#Override
public User deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException {
// Get the "content" element from the parsed JSON
JsonElement content = je.getAsJsonObject().get("data");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(content, User.class);
}
}
The JSON response:
{
"success":true,
"data":[
{
"id":"1",
"username":"User1"
},
{
"id":"2",
"username":"User2"
}
]
}
Within Retrofit's success callback, I'm not sure how to actually loop through the data's items and extract the data from it (like the person's username).
Create this model classes:
private class ResponseData {
public boolean success;
public List<User> data;
}
private class User {
public String id;
public String username;
}
Now you can do this:
final RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(URL)
.build();
final ApiEndpointInterface apiService = restAdapter.create(ApiEndpointInterface.class);
apiService.getJsonData(1, new Callback<ResponseData>() {
#Override
public void success(ResponseData responseData, Response response) {
for (User u : responseData.data) {
String name = u.username;
// etc
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
}
});

Categories

Resources