I'm using Retrofit 2 in Android Studio to get stop information in JSON form from the CUMTD api for stops by search and for some reason the connection keeps on failing, are the query parameters and everything else correct, i used to the JSON to pojo converter for the model class so it should be correct or is it something from main activity? Heres the URL I'm trying to connect to https://developer.cumtd.com/api/v2.2/json/GetStopsBySearch?key=b7cd7d8c64b24b4f8415aeb57d6f7f74&query=transit%20plaza
my code:
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("changeset_id")
#Expose
private String changesetId;
#SerializedName("new_changeset")
#Expose
private Boolean newChangeset;
#SerializedName("time")
#Expose
private String time;
#SerializedName("status")
#Expose
private Status status;
#SerializedName("rqst")
#Expose
private Rqst rqst;
#SerializedName("stops")
#Expose
private List<Stop> stops = null;
public String getChangesetId() {
return changesetId;
}
public void setChangesetId(String changesetId) {
this.changesetId = changesetId;
}
public Boolean getNewChangeset() {
return newChangeset;
}
public void setNewChangeset(Boolean newChangeset) {
this.newChangeset = newChangeset;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Rqst getRqst() {
return rqst;
}
public void setRqst(Rqst rqst) {
this.rqst = rqst;
}
public List<Stop> getStops() {
return stops;
}
public void setStops(List<Stop> stops) {
this.stops = stops;
}
}
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.List;
import java.util.Random;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static android.R.attr.x;
import static android.media.CamcorderProfile.get;
import static com.example.neelpatel.weatherapp.MTDApi.retrofit;
public class MainActivity extends AppCompatActivity {
String key= "b7cd7d8c64b24b4f8415aeb57d6f7f74";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//Starts Retrofit
final MTDApi mtdApi = MTDApi.retrofit.create(MTDApi.class);
//Sets up Button and EditText for use in this class
final EditText edit = (EditText) findViewById(R.id.edit);
Button requestButton = (Button) findViewById(R.id.button);
//Behavior once button is clicked
requestButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String s = edit.getText().toString();
//Sets up up the API call
Call<List<Example>> call = mtdApi.loadStops(key,s);
//Runs the call on a different thread
call.enqueue(new Callback<List<Example>>() {
#Override
//Once the call has finished
public void onResponse(Call<List<Example>> call, Response<List<Example>> response) {
if (response.isSuccessful()) {
//Gets the list of stops
List<Example> stops = response.body();
List<Stop> list = stops.get(0).getStops();
String text = list.get(0).getStopId();
edit.setText(text);
} else {
// show error message
Log.e("RequestCall", "Request failed");
}
}
#Override
//If the call failed
public void onFailure(Call<List<Example>> call, Throwable t) {
edit.setText("Request Failed");
Log.e("RequestCall", "Request failed");
}
});
}
});
}
}
import java.util.List;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
/**
* Class that details the request(s) that we will call
*/
public interface MTDApi{
#GET("GetStopsBySearch")
Call<List<Example>> loadStops(#Query("key") String key,
#Query("query") String query);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://developer.cumtd.com/api/v2.2/json/")
.addConverterFactory(GsonConverterFactory.create())
.build();
}
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Params {
#SerializedName("count")
#Expose
private Integer count;
#SerializedName("query")
#Expose
private String query;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
import com.example.neelpatel.weatherapp.Params;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Rqst {
#SerializedName("method")
#Expose
private String method;
#SerializedName("params")
#Expose
private Params params;
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Params getParams() {
return params;
}
public void setParams(Params params) {
this.params = params;
}
}
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Status {
#SerializedName("code")
#Expose
private Integer code;
#SerializedName("msg")
#Expose
private String msg;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
import java.util.List;
import com.example.neelpatel.weatherapp.StopPoint;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Stop {
#SerializedName("stop_id")
#Expose
private String stopId;
#SerializedName("stop_name")
#Expose
private String stopName;
#SerializedName("code")
#Expose
private String code;
#SerializedName("percent_match")
#Expose
private Integer percentMatch;
#SerializedName("stop_points")
#Expose
private List<StopPoint> stopPoints = null;
public String getStopId() {
return stopId;
}
public void setStopId(String stopId) {
this.stopId = stopId;
}
public String getStopName() {
return stopName;
}
public void setStopName(String stopName) {
this.stopName = stopName;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Integer getPercentMatch() {
return percentMatch;
}
public void setPercentMatch(Integer percentMatch) {
this.percentMatch = percentMatch;
}
public List<StopPoint> getStopPoints() {
return stopPoints;
}
public void setStopPoints(List<StopPoint> stopPoints) {
this.stopPoints = stopPoints;
}
}
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class StopPoint {
#SerializedName("code")
#Expose
private String code;
#SerializedName("stop_id")
#Expose
private String stopId;
#SerializedName("stop_lat")
#Expose
private Double stopLat;
#SerializedName("stop_lon")
#Expose
private Double stopLon;
#SerializedName("stop_name")
#Expose
private String stopName;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getStopId() {
return stopId;
}
public void setStopId(String stopId) {
this.stopId = stopId;
}
public Double getStopLat() {
return stopLat;
}
public void setStopLat(Double stopLat) {
this.stopLat = stopLat;
}
public Double getStopLon() {
return stopLon;
}
public void setStopLon(Double stopLon) {
this.stopLon = stopLon;
}
public String getStopName() {
return stopName;
}
public void setStopName(String stopName) {
this.stopName = stopName;
}
}
You didn't provide much (any) information about the failure itself, but it's pretty easy to spot at least one possible bug. In the response you expect a list of Example objects:
Call<List<Example>> call = mtdApi.loadStops(key,s);
This is not good since you can cleary see in the documentation of GetStopsBySearch that the returned JSON object is not a list (i.e. not a JSON array). Fixing this is really easy, just expect a single Example object instead of a list of those:
Call<Example> call = mtdApi.loadStops(key,s);
This obviously means that you have to change the signature of the Callback but you don't need extra info for that.
Related
I have access to an external API that can in some cases send JSON (a structure in the first class), and maybe in some cases not a valid object of this type - {}. I want to convert this invalid object to the first one, as in the class below, and use a custom deserialization method. But for some reason, my application does not fail if you put a debugging point there. Why is that? As an instruction, I used this example - https://gist.github.com/sghill/2395319
import com.example.MyDeserializer;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import java.util.List;
#JsonDeserialize(using = MyDeserializer.class)
public class Response {
public List<Error> errors;
public class Error{
public int status;
public String code;
public String title;
public String detail;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
}
public List<Error> getErrors() {
return errors;
}
public void setErrors(List<Error> errors) {
this.errors = errors;
}
}
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
public class ResponseDeserializer extends JsonDeserializer<Response> {
#Override
public Response deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
JsonNode node = jsonParser.readValueAsTree();
ObjectMapper mapper = new ObjectMapper();
if (node.asText().isEmpty()) {
return new Response();
}
return mapper.readValue(node, Response.class);
}
}
Here is my login activity
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.sti.Models.responsemodel;
import com.example.sti.Retrofit.ApiClient;
import com.example.sti.Retrofit.ApiInterface;
import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class LoginActivity extends AppCompatActivity {
ApiInterface apiInterface;
#BindView(R.id.editTextEmail) EditText editTextEmail;
#BindView(R.id.editTextPassword) EditText editTextPassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
apiInterface= ApiClient.getApiClient().create(ApiInterface.class);
}
public void loginUser(View view)
{
Call<responsemodel> responsemodelCall=apiInterface.loginUser(editTextEmail.getText().toString(),editTextPassword.getText().toString());
responsemodelCall.enqueue(new Callback<responsemodel>() {
#Override
public void onResponse(Call<responsemodel> call, Response<responsemodel> response)
{
if (response.body()!=null)
{
responsemodel responsemodel=response.body();
if (responsemodel.isresponse_code())
{
Toast.makeText(LoginActivity.this,"login successful",Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(LoginActivity.this,"user not found",Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onFailure(Call<responsemodel> call, Throwable t)
{
Toast.makeText(LoginActivity.this,"Error Could Not Connect",Toast.LENGTH_LONG).show();
}
});
}
}
Here is my login api file
<?php
class Api extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('admin_model');
$this->load->helper('url_helper');
$this->load->library('session');
}
public function login() {
$login=array(
'email'=>$this->input->post('email'),
'password'=>md5($this->input->post('password')),
);
if($login['email']=="" || $login['password']=="")
{
$temp["response_code"]="0";
$temp["message"]="Enter Data";
$temp["status"]="failure";
echo json_encode($temp);
}
else
{
$temp = array();
$data=$this->admin_model->login_usera($login['email'],$login['password']);
if($data)
{
$temp["response_code"]="1";
$temp["message"]="user login success";
$temp["status"]="success";
$temp["user_id"]=$data['id'];
$temp["user_token"]=md5(uniqid(rand(), true));
echo json_encode($temp);
}
else
{
$temp["response_code"]="0";
$temp["message"]="user login failure";
$temp["status"]="failure";
$temp["user_token"]=md5(uniqid(rand(), true));
echo json_encode($temp);
}
}
}
}
Here is my apiclient.java file:
public class ApiClient {
public static final String BASE_URL="https://sparkstoideas.com/student/"; // actual base url is here..
public static Retrofit retrofit=null;
public static Retrofit getApiClient(){
if(retrofit==null){
Gson gson=new GsonBuilder()
.setLenient()
.create();
retrofit =new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
This is the apiinterface.java file:
public interface ApiInterface
{
#FormUrlEncoded
#POST("api/login") //next url upon base url to continue..
Call<responsemodel> loginUser(#Field("email")String email,
#Field("password")String password);
}
And here is responsemodel of the api:
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class responsemodel {
#Expose
#SerializedName("email")
private String email;
#Expose
#SerializedName("password")
private String password;
#Expose
#SerializedName("response_code")
private boolean response_code;
#Expose
#SerializedName("message")
private String message;
#Expose
#SerializedName("status")
private String status;
#Expose
#SerializedName("user_id")
private int user_id;
#Expose
#SerializedName("user_token")
private String user_token;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isresponse_code() {
return response_code;
}
public void setresponse_code(boolean response_code) {
this.response_code = response_code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public String getUser_token() {
return user_token;
}
public void setUser_token(String user_token) {
this.user_token = user_token;
}
}
I am a total beginner in android please help me why is not working..
I have an android app that fetches data from a database using an access token. I have successfully setup the oAuth2 side of the app and can login with credentials and store the access token to be used with GET requests. Now I am trying to fetch some customer data from the database but the response returns the package name and not the customer data.
Below you can find my classes:
CustomerResponse.java
package com.example.helper.retrofit.oauth2.response;
public class CustomerResponse {
private Integer id;
private String name;
private String tel;
private String email;
private String address1;
private String address2;
private String address3;
private String town;
private String county;
private String postcode;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress1() {
return address1;
}
public void setAddress1(String address1) {
this.address1 = address1;
}
public String getAddress2() {
return address2;
}
public void setAddress2(String address2) {
this.address2 = address2;
}
public String getAddress3() {
return address3;
}
public void setAddress3(String address3) {
this.address3 = address3;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
}
ViewCustomers.java
package com.example.packagename;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
import com.example.helper.retrofit.oauth2.OauthConstant;
import com.example.helper.retrofit.oauth2.response.CustomerResponse;
import com.example.helper.retrofit.oauth2.service.CustomerService;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ViewCustomers extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_customers);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(OauthConstant.DATA_SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
CustomerService customerService = retrofit.create(CustomerService.class);
Call<CustomerResponse> call = customerService.getCustomers();
call.enqueue(new Callback<CustomerResponse>() {
#Override
public void onResponse(Call<CustomerResponse> call, retrofit2.Response<CustomerResponse> response) {
if (response.isSuccessful()) {
Toast.makeText(ViewCustomers.this, response.body().toString(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(ViewCustomers.this, "Not successful!", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<CustomerResponse> call, Throwable t) {
Toast.makeText(ViewCustomers.this, "Failed!", Toast.LENGTH_LONG).show();
}
});
}
}
cCustomerService.java
package com.example.packagename.helper.retrofit.oauth2.client;
import android.content.Context;
import android.content.SharedPreferences;
import java.io.IOException;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import static com.example.MainActivity.access;
import static com.example.MainActivity.mypreference;
public class cCustomerService {
private Context mContext;
SharedPreferences sharedPreferences;
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
mContext.getSharedPreferences(mypreference, Context.MODE_PRIVATE);
RequestBody formBody = new FormBody.Builder()
.add("access_token", sharedPreferences.getString(access, ""))
.build();
String postBodyToString = bodyToString(request.body());
postBodyToString += ((postBodyToString.length() > 0) ? "&" : "") + bodyToString(formBody);
request = requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyToString))
.build();
return chain.proceed(request);
}
}).build();
public static String bodyToString(final RequestBody requestBody) {
try {
final RequestBody copy = requestBody;
final Buffer buffer = new Buffer();
if (copy != null) {
copy.writeTo(buffer);
} else {
return "";
}
return buffer.readUtf8();
} catch (IOException e) {
return "didn't work";
}
}
}
Customerservice.java
package com.example.helper.retrofit.oauth2.service;
import com.example.helper.retrofit.oauth2.response.CustomerResponse;
import retrofit2.Call;
import retrofit2.http.GET;
public interface CustomerService {
#GET("customer/")
Call<CustomerResponse> getCustomers();
}
The value returned is com.example.packagename.helper.retrofit.oauth2.response.CustomerResponse#a6bc5ca each time I run the request it returns some different digits at the end, I'm not sure if this has any relevance.
Is there something I'm doing wrong?
Hi everybody and thanks for helping me,
I'm trying to fetch data from an api url "https://api.stackexchange.com/2.2/search?order=desc&sort=creation&site=stackoverflow&tagged=android" and I don't know what I am missing.
I keep on getting an error saying that I am pointing to a null object, but it is not supposed to be null.
That is the error message
`
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.finalhomework, PID: 5005
java.lang.NullPointerException: Attempt to invoke interface method 'java.util.Iterator java.util.List.iterator()' on a null object reference
at com.example.finalhomework.view.SearchActivity$1.onResponse(SearchActivity.java:46)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$3wC8FyV4pyjrzrYL5U0mlYiviZw.run(lambda)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)`
That is the results page which is supposed to get all the item
`
package com.example.finalhomework.model;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class StackOverflowPageResult implements Serializable
{
#SerializedName("StackOverflowItem")
#Expose
private List<StackOverflowItem> items = null;
#SerializedName("has_more")
#Expose
private Boolean hasMore;
#SerializedName("quota_max")
#Expose
private Integer quotaMax;
#SerializedName("quota_remaining")
#Expose
private Integer quotaRemaining;
private final static long serialVersionUID = -263378404000205617L;
public List<StackOverflowItem> getStackOverflowItem() {
return items;
}
public void setItems(List<StackOverflowItem> items) {
this.items = items;
}
public Boolean getHasMore() {
return hasMore;
}
public void setHasMore(Boolean hasMore) {
this.hasMore = hasMore;
}
public Integer getQuotaMax() {
return quotaMax;
}
public void setQuotaMax(Integer quotaMax) {
this.quotaMax = quotaMax;
}
public Integer getQuotaRemaining() {
return quotaRemaining;
}
public void setQuotaRemaining(Integer quotaRemaining) {
this.quotaRemaining = quotaRemaining;
}
}`
That is the Item itself:
`
package com.example.finalhomework.model;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class StackOverflowItem implements Serializable
{
#SerializedName("tags")
#Expose
private List<String> tags = null;
#SerializedName("owner")
#Expose
private Owner owner;
#SerializedName("is_answered")
#Expose
private Boolean isAnswered;
#SerializedName("view_count")
#Expose
private Integer viewCount;
#SerializedName("answer_count")
#Expose
private Integer answerCount;
#SerializedName("score")
#Expose
private Integer score;
#SerializedName("last_activity_date")
#Expose
private Integer lastActivityDate;
#SerializedName("creation_date")
#Expose
private Integer creationDate;
#SerializedName("question_id")
#Expose
private Integer questionId;
#SerializedName("content_license")
#Expose
private String contentLicense;
#SerializedName("link")
#Expose
private String link;
#SerializedName("title")
#Expose
private String title;
#SerializedName("last_edit_date")
#Expose
private Integer lastEditDate;
#SerializedName("accepted_answer_id")
#Expose
private Integer acceptedAnswerId;
#SerializedName("closed_date")
#Expose
private Integer closedDate;
#SerializedName("closed_reason")
#Expose
private String closedReason;
private final static long serialVersionUID = 2088551364601451752L;
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public Owner getOwner() {
return owner;
}
public void setOwner(Owner owner) {
this.owner = owner;
}
public Boolean getIsAnswered() {
return isAnswered;
}
public void setIsAnswered(Boolean isAnswered) {
this.isAnswered = isAnswered;
}
public Integer getViewCount() {
return viewCount;
}
public void setViewCount(Integer viewCount) {
this.viewCount = viewCount;
}
public Integer getAnswerCount() {
return answerCount;
}
public void setAnswerCount(Integer answerCount) {
this.answerCount = answerCount;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public Integer getLastActivityDate() {
return lastActivityDate;
}
public void setLastActivityDate(Integer lastActivityDate) {
this.lastActivityDate = lastActivityDate;
}
public Integer getCreationDate() {
return creationDate;
}
public void setCreationDate(Integer creationDate) {
this.creationDate = creationDate;
}
public Integer getQuestionId() {
return questionId;
}
public void setQuestionId(Integer questionId) {
this.questionId = questionId;
}
public String getContentLicense() {
return contentLicense;
}
public void setContentLicense(String contentLicense) {
this.contentLicense = contentLicense;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getLastEditDate() {
return lastEditDate;
}
public void setLastEditDate(Integer lastEditDate) {
this.lastEditDate = lastEditDate;
}
public Integer getAcceptedAnswerId() {
return acceptedAnswerId;
}
public void setAcceptedAnswerId(Integer acceptedAnswerId) {
this.acceptedAnswerId = acceptedAnswerId;
}
public Integer getClosedDate() {
return closedDate;
}
public void setClosedDate(Integer closedDate) {
this.closedDate = closedDate;
}
public String getClosedReason() {
return closedReason;
}
public void setClosedReason(String closedReason) {
this.closedReason = closedReason;
}
}`
That is the Retrofit builder with the url:
`
package com.example.finalhomework.network;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitInstance {
private static Retrofit retrofit;
private static final String BASE_URL ="https://api.stackexchange.com/2.2/";
public static Retrofit getRetrofitInstance(){
if (retrofit == null){
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}`
That is the interface with the url's arguments:
`
package com.example.finalhomework.network;
import com.example.finalhomework.model.StackOverflowPageResult;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface GetStackOverflowItemDataService {
#GET("search")
Call<StackOverflowPageResult> getStackOverflowItem(
#Query("tagged") String tagged,
#Query("site") String site,
#Query("sort") String sort,
#Query("order") String order
);
}`
And here we've got the class which is supposed to get the total result, and I put a Log.i in order to check if everything is in order and the stackOverflowItems is null:
`
package com.example.finalhomework.view;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.os.Bundle;
import android.util.Log;
import com.example.finalhomework.R;
import com.example.finalhomework.model.StackOverflowItem;
import com.example.finalhomework.model.StackOverflowPageResult;
import com.example.finalhomework.network.GetStackOverflowItemDataService;
import com.example.finalhomework.network.RetrofitInstance;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class SearchActivity extends AppCompatActivity {
Toolbar toolbar;
private GetStackOverflowItemDataService stackOverflowItemDataService;
List<StackOverflowItem> stackOverflowItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
setToolbarBack();
stackOverflowItemDataService = RetrofitInstance.getRetrofitInstance().create(GetStackOverflowItemDataService.class);
stackOverflowItemDataService.getStackOverflowItem("android", "stackoverflow", "creation", "desc")
.enqueue(new Callback<StackOverflowPageResult>() {
#Override
public void onResponse(Call<StackOverflowPageResult> call, Response<StackOverflowPageResult> response) {
StackOverflowPageResult stackOverflowPageResult = response.body();
stackOverflowItems = stackOverflowPageResult.getStackOverflowItem();
for (StackOverflowItem s : stackOverflowItems) {
Log.i("Item StackOverflow :", s.getTitle());
}
}
#Override
public void onFailure(Call<StackOverflowPageResult> call, Throwable t) {
}
});
}`
Again thanks for the help
There is mismatch between JSON data variable and your #SerializedName("StackOverflowItem")
So make the changes to match the SerializedName, code as follows -
public class StackOverflowPageResult implements Serializable {
#SerializedName("items")
private List<StackOverflowItem> items;
#SerializedName("has_more")
private Boolean hasMore;
#SerializedName("quota_max")
private Integer quotaMax;
#SerializedName("quota_remaining")
private Integer quotaRemaining;
// your further code here
//.............
}
SerializedName is only required when you are going to take variable name different from JSON object, otherwise you can skip #SerializedName tag as well.
One more thing I suggest, I you are not going to call excludeFieldsWithoutExposeAnnotation() in your GsonBuilder class, then there is no need for #Expose tag.
The Gson #Expose annotation can be used to mark a field to be exposed or not (included or not) for serialized or deserialized. The #Expose annotation can take two parameters and each parameter is a boolean which can take either the value true or false. In order to get GSON to react to the #Expose annotations we must create a Gson instance using the GsonBuilder class and need to call the excludeFieldsWithoutExposeAnnotation() method, it configures Gson to exclude all fields from consideration for serialization or deserialization that do not have the Expose annotation.
Happy Coding !
I have a JSON object like the following:
...
{
"url": "checkout.bodenusa.com/en-US"
},
{
"url": [
".bonton.com/checkout/",
".bonton.com/CheckoutView"
]
}
...
How should my Java class look like for Response server.
I try this snippet, but it is incorrect:
#SerializedName("url")
#Expose
private List<String> urlList = null;
#SerializedName("url")
#Expose
private String url;
Create a model like
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class Model {
#SerializedName("url")
#Expose
private List<String> url = null;
#SerializedName("apply")
#Expose
private Apply apply;
#SerializedName("controls")
#Expose
private Controls controls;
#SerializedName("remove")
#Expose
private Remove remove;
public List<String> getUrl() {
return url;
}
public void setUrl(List<String> url) {
this.url = url;
}
public Apply getApply() {
return apply;
}
public void setApply(Apply apply) {
this.apply = apply;
}
public Controls getControls() {
return controls;
}
public void setControls(Controls controls) {
this.controls = controls;
}
public Remove getRemove() {
return remove;
}
public void setRemove(Remove remove) {
this.remove = remove;
}
public class Controls {
#SerializedName("promo")
#Expose
private String promo;
#SerializedName("total")
#Expose
private String total;
#SerializedName("orderTotal")
#Expose
private String orderTotal;
#SerializedName("coupon")
#Expose
private String coupon;
public String getPromo() {
return promo;
}
public void setPromo(String promo) {
this.promo = promo;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
public String getOrderTotal() {
return orderTotal;
}
public void setOrderTotal(String orderTotal) {
this.orderTotal = orderTotal;
}
public String getCoupon() {
return coupon;
}
public void setCoupon(String coupon) {
this.coupon = coupon;
}
}
public class Remove {
#SerializedName("type")
#Expose
private String type;
#SerializedName("submit")
#Expose
private String submit;
#SerializedName("timeout")
#Expose
private Integer timeout;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSubmit() {
return submit;
}
public void setSubmit(String submit) {
this.submit = submit;
}
public Integer getTimeout() {
return timeout;
}
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
}
public class Apply {
#SerializedName("type")
#Expose
private String type;
#SerializedName("submit")
#Expose
private String submit;
#SerializedName("timeout")
#Expose
private Integer timeout;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSubmit() {
return submit;
}
public void setSubmit(String submit) {
this.submit = submit;
}
public Integer getTimeout() {
return timeout;
}
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
}
}
Use this class along with a Custom TypeAdapter for Gson .Then it will work for both List and Object response .
ArrayAdapter class
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class ArrayAdapterFactory implements TypeAdapterFactory {
#Override
#SuppressWarnings({"unchecked", "rawtypes"})
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
TypeAdapter<T> typeAdapter = null;
try {
if (type.getRawType() == List.class || type.getRawType() == ArrayList.class) {
typeAdapter = new ArrayAdapter(gson,
(Class) ((ParameterizedType) type.getType())
.getActualTypeArguments()[0]);
}
} catch (Exception e) {
e.printStackTrace();
}
return typeAdapter;
}
}
ArrayAdapterFactory class
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
class ArrayAdapter<T> extends TypeAdapter<List<T>> {
private Class<T> adapterclass;
private Gson gson;
public ArrayAdapter(Gson gson, Class<T> adapterclass) {
this.adapterclass = adapterclass;
this.gson = gson;
}
#Override
public List<T> read(JsonReader reader) throws IOException {
List<T> list = new ArrayList<T>();
final JsonToken token = reader.peek();
System.out.println(token);
// Handling of Scenario 2( Check JavaDoc for the class) :
if (token == JsonToken.STRING || token == JsonToken.NUMBER ||
token == JsonToken.BOOLEAN) {
T inning = (T) gson.fromJson(reader, adapterclass);
list.add(inning);
} else if (token == JsonToken.BEGIN_OBJECT) {
// Handling of Scenario 1(Check JavaDoc for the class) :
T inning = (T) gson.fromJson(reader, adapterclass);
list.add(inning);
} else if (token == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
while (reader.hasNext()) {
#SuppressWarnings("unchecked")
T inning = (T) gson.fromJson(reader, adapterclass);
list.add(inning);
}
reader.endArray();
}
return list;
}
#Override
public void write(JsonWriter writer, List<T> value) throws IOException {
}
}
And register the adapter factory like this,
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create();
public class Example {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Use this link to generate POJO's