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
Related
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 !
Here's an example of my JSON:
{
"status": "ok",
"rowCount": 60,
"pageCount": 6,
"value": [{
"CustomerID": 1911,
"CustomerTypeID": 3,
...
}
]
}
My POJO:
#SerializedName("CustomerID")
public Integer CustomerID;
#SerializedName("CustomerTypeID")
public Integer CustomerTypeID;
I want to pull everything under value.
How do I do this using Google's GSON?
I've tried doing it as I would normally, but for, obvious reasons, it didn't work:
Type collectionType = new TypeToken<ArrayList<Customer>>() {}.getType();
return gson.fromJson(json, collectionType);
You can not skip root JSON object. The simplest solution in this case is - create root POJO:
class Response {
#SerializedName("value")
private List<Customer> customers;
// getters, setters
}
And you can use it as below:
return gson.fromJson(json, Response.class).getCustomers();
You don't need to worry writing your own POJO.
just visit http://www.jsonschema2pojo.org/
and paste here your JSON data, it'll automatically return you converted classes as below
-----------------------------------com.example.Example.java-----------------------------------
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("status")
#Expose
private String status;
#SerializedName("rowCount")
#Expose
private Integer rowCount;
#SerializedName("pageCount")
#Expose
private Integer pageCount;
#SerializedName("value")
#Expose
private List<Value> value = null;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getRowCount() {
return rowCount;
}
public void setRowCount(Integer rowCount) {
this.rowCount = rowCount;
}
public Integer getPageCount() {
return pageCount;
}
public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}
public List<Value> getValue() {
return value;
}
public void setValue(List<Value> value) {
this.value = value;
}
}
-----------------------------------com.example.Value.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Value {
#SerializedName("CustomerID")
#Expose
private Integer customerID;
#SerializedName("CustomerTypeID")
#Expose
private Integer customerTypeID;
public Integer getCustomerID() {
return customerID;
}
public void setCustomerID(Integer customerID) {
this.customerID = customerID;
}
public Integer getCustomerTypeID() {
return customerTypeID;
}
public void setCustomerTypeID(Integer customerTypeID) {
this.customerTypeID = customerTypeID;
}
}
The above two classes are auto generated by website.
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class ExampleClass {
#SerializedName("status")
#Expose
private String status;
#SerializedName("rowCount")
#Expose
private int rowCount;
#SerializedName("pageCount")
#Expose
private int pageCount;
#SerializedName("value")
#Expose
private List<Value> value = null;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getRowCount() {
return rowCount;
}
public void setRowCount(int rowCount) {
this.rowCount = rowCount;
}
public int getPageCount() {
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public List<Value> getValue() {
return value;
}
public void setValue(List<Value> value) {
this.value = value;
}
}
-----------------------------------Value.java-----------------------------------
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Value {
#SerializedName("CustomerID")
#Expose
private int customerID;
#SerializedName("CustomerTypeID")
#Expose
private int customerTypeID;
public int getCustomerID() {
return customerID;
}
public void setCustomerID(int customerID) {
this.customerID = customerID;
}
public int getCustomerTypeID() {
return customerTypeID;
}
public void setCustomerTypeID(int customerTypeID) {
this.customerTypeID = customerTypeID;
}
}
/********* parsing with Gson ******/
GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.create();
ExampleClass resultObj = gson.fromJson(jsonObject.toString(), ExampleClass.class);
List<Value> yourListOfCustomerValues = resultObj.getValue();
You can refer to this amazing post on mapping of arrays and lists of objects with Gson by Norman Peitek
Basics of Gson, model annotations and mapping of nested objects
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.
I have an Android application that gets a json from a http call and looks like this:
{
"string_1":{
"prop_1":"value",
"prop_2":"value"
},
"string_2":{
"prop_1":"value",
"prop_2":"value"
},
...
"string_n":{
"prop_1":"value",
"prop_2":"value"
}
}
Here's the java class I wrote to use the data in my code:
public class FooClass implements Serializable {
private LinkedHashMap<String, FooObject> objectsMap;
public LinkedHashMap<String, FooObject> getObjectsMap() {
return objectsMap;
}
}
where FooObject is:
public class FooObject implements Serializable {
#SerializedName("prop_1")
private String property1;
#SerializedName("prop_2")
private String property2;
public String getProperty1() {
return property1;
}
public String getProperty1() {
return property1;
}
}
But since my json doesn't have an element called "objectsMap" my linked hash map from FooClass is always null.
What class structure should I use for this json structure?
Thank you.
UPDATE:
I have managed to solve my problem. I use retrofit 1.9, and make the method return a result of type LinkedHashMap and it solved my problem.
Better and more feasible is to change your response structure and have an Array rather than string_1, string_2... string_n. If you can't do that you will have to iterate through all the possible keys and save the response something like this
jObject = new JSONObject(response);
Iterator<?> keys = jObject.keys();
while( keys.hasNext() ) {
String key = (String)keys.next();
if ( jObject.get(key) instanceof JSONObject ) {
// do your stuff here
}
}
-----------------------------------com.example.Example.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("string_1")
#Expose
private String1 string1;
#SerializedName("string_2")
#Expose
private String2 string2;
#SerializedName("string_n")
#Expose
private StringN stringN;
public String1 getString1() {
return string1;
}
public void setString1(String1 string1) {
this.string1 = string1;
}
public String2 getString2() {
return string2;
}
public void setString2(String2 string2) {
this.string2 = string2;
}
public StringN getStringN() {
return stringN;
}
public void setStringN(StringN stringN) {
this.stringN = stringN;
}
}
-----------------------------------com.example.String1.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class String1 {
#SerializedName("prop_1")
#Expose
private String prop1;
#SerializedName("prop_2")
#Expose
private String prop2;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
}
-----------------------------------com.example.String2.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class String2 {
#SerializedName("prop_1")
#Expose
private String prop1;
#SerializedName("prop_2")
#Expose
private String prop2;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
}
-----------------------------------com.example.StringN.java-----------------------------------
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class StringN {
#SerializedName("prop_1")
#Expose
private String prop1;
#SerializedName("prop_2")
#Expose
private String prop2;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public String getProp2() {
return prop2;
}
public void setProp2(String prop2) {
this.prop2 = prop2;
}
}
Hope it helps and you can use http://www.jsonschema2pojo.org/
If you're using a SerializedName annotation in your Response class which you're trying to map, just delete it and map your Json Response to
public class FooClass implements Serializable {
private Map<String, FooObject> objectsMap;
public Map<String, FooObject> getObjectsMap() {
return objectsMap;
}
}
I have the below pojo which I'm trying to serialize and deserialize using spring support for jackson processor,Below is my POJO class
public class Contract {
String term;
private List<Payment> paymentList=new ArrayList<Payment>();
public String getTerm() {
return term;
}
public void setTerm(String term) {
this.term = term;
}
public List<Payment> getPaymentList() {
return paymentList;
}
public void setPaymentList(List<Payment> paymentList) {
this.paymentList = paymentList;
}
}
In the above class if there is a list,I am getting null pointer exception when I am using JUnit test cases mentioned below:
package com.budco.vsc.jsonmapping;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.samples.mvc.ajax.account.Contract;
import org.springframework.samples.mvc.ajax.json.ConversionServiceAwareObjectMapper;
import org.springframework.util.Assert;
public class ContractJsonBindingTests{
Logger log = LoggerFactory.getLogger(ContractJsonBindingTests.class);
private MappingJacksonHttpMessageConverter converter;
private ObjectMapper objectMapper;
private String testPayload = "{\"term\":\"krish\"}";
#Before
public void setUp() {
FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean();
factoryBean.afterPropertiesSet();
ConversionService conversionService = factoryBean.getObject();
objectMapper = new ConversionServiceAwareObjectMapper(conversionService);
converter = new MappingJacksonHttpMessageConverter();
converter.setObjectMapper(objectMapper);
}
#Test
#SuppressWarnings("unchecked")
public void testAnnotationDrivenJsonConversion() throws Exception {
MockHttpInputMessage inputMessage = new MockHttpInputMessage(testPayload.getBytes("UTF-8"));
MediaType jsonType = new MediaType("application", "json");
inputMessage.getHeaders().setContentType(jsonType);
Contract contract = (Contract) converter.read((Class) Contract.class, inputMessage);
Assert.notNull(contract);
log.debug(contract.toString());
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
converter.write(contract, jsonType, outputMessage);
log.debug(outputMessage.getBody().toString());
assertEquals("Incoming and outgoing JSON representations expected to match", testPayload, outputMessage.getBody().toString());
}
private static class MockHttpInputMessage implements HttpInputMessage {
private final HttpHeaders headers = new HttpHeaders();
private final InputStream body;
public MockHttpInputMessage(byte[] contents) {
Assert.notNull(contents, "'contents' must not be null");
this.body = new ByteArrayInputStream(contents);
}
public HttpHeaders getHeaders() {
return headers;
}
public InputStream getBody() throws IOException {
return body;
}
}
public class MockHttpOutputMessage implements HttpOutputMessage {
private final HttpHeaders headers = new HttpHeaders();
private final ByteArrayOutputStream body = new ByteArrayOutputStream();
public HttpHeaders getHeaders() {
return headers;
}
public OutputStream getBody() throws IOException {
return body;
}
public byte[] getBodyAsBytes() {
return body.toByteArray();
}
public String getBodyAsString(Charset charset) {
byte[] bytes = getBodyAsBytes();
return new String(bytes, charset);
}
}
}
The stack trace is
java.lang.NullPointerException
at org.springframework.samples.mvc.ajax.json.FormatAnnotationIntrospector.findDeserializer(FormatAnnotationIntrospector.java:33)
at org.codehaus.jackson.map.AnnotationIntrospector$Pair.findDeserializer(AnnotationIntrospector.java:1058)
at org.codehaus.jackson.map.deser.BasicDeserializerFactory.findDeserializerFromAnnotation(BasicDeserializerFactory.java:462)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.constructSettableProperty(BeanDeserializerFactory.java:606)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:460)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:149)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:116)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:342)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:264)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:244)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:111)
at org.codehaus.jackson.map.deser.StdDeserializer.findDeserializer(StdDeserializer.java:482)
at org.codehaus.jackson.map.deser.BeanDeserializer.resolve(BeanDeserializer.java:271)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._resolveDeserializer(StdDeserializerProvider.java:348)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:303)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:244)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:111)
at org.codehaus.jackson.map.deser.BasicDeserializerFactory.createCollectionDeserializer(BasicDeserializerFactory.java:182)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:332)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:264)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:244)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:111)
at org.codehaus.jackson.map.deser.StdDeserializer.findDeserializer(StdDeserializer.java:482)
at org.codehaus.jackson.map.deser.BeanDeserializer.resolve(BeanDeserializer.java:271)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._resolveDeserializer(StdDeserializerProvider.java:348)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:303)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:244)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:111)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:127)
at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2046)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:1980)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1331)
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:124)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
at com.budco.vsc.jsonmapping.ContractJsonBindingTests.testAnnotationDrivenJsonConversion(ContractJsonBindingTests.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Note:- If I'm removing the list property(paymentList) from the POJO then there is no problem. That means the above is not working when the POJO content some collection properties.If any body have any idea please help me.
EDIT:
The payment class
public class Payment {
private BigDecimal amount;
private String payType;
private String transactionType;
private String chargeOrCancelFlag;
private String type;
private String authCode;
private Date authRequestDate;
private String authStatus;
private String authTransactioncode;
private SystemUser systemUser;
private String mailOrEmailInvoice;
private String monthlyBillOnDay;
private CreditCard creditCard;
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getPayType() {
return payType;
}
public void setPayType(String payType) {
this.payType = payType;
}
public String getTransactionType() {
return transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public String getChargeOrCancelFlag() {
return chargeOrCancelFlag;
}
public void setChargeOrCancelFlag(String chargeOrCancelFlag) {
this.chargeOrCancelFlag = chargeOrCancelFlag;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
public Date getAuthRequestDate() {
return authRequestDate;
}
public void setAuthRequestDate(Date authRequestDate) {
this.authRequestDate = authRequestDate;
}
public String getAuthStatus() {
return authStatus;
}
public void setAuthStatus(String authStatus) {
this.authStatus = authStatus;
}
public String getAuthTransactioncode() {
return authTransactioncode;
}
public void setAuthTransactioncode(String authTransactioncode) {
this.authTransactioncode = authTransactioncode;
}
public SystemUser getSystemUser() {
return systemUser;
}
public void setSystemUser(SystemUser systemUser) {
this.systemUser = systemUser;
}
public String getMailOrEmailInvoice() {
return mailOrEmailInvoice;
}
public void setMailOrEmailInvoice(String mailOrEmailInvoice) {
this.mailOrEmailInvoice = mailOrEmailInvoice;
}
public String getMonthlyBillOnDay() {
return monthlyBillOnDay;
}
public void setMonthlyBillOnDay(String monthlyBillOnDay) {
this.monthlyBillOnDay = monthlyBillOnDay;
}
public CreditCard getCreditCard() {
return creditCard;
}
public void setCreditCard(CreditCard creditCard) {
this.creditCard = creditCard;
}
}
The credit card class
public class CreditCard {
private String type;
private String cardNumber;
private String name;
private String securityCode;
private String expirationDate;
private String firstFourDigit;
private String secondFourDigit;
private String thirdFourDigit;
private String lastFourDigits;
private String zipCode;
public void setMonth(String month){
if(expirationDate==null)
expirationDate=month;
else
expirationDate=month+"/"+expirationDate;
}
public void setYear(String year){
if(expirationDate==null)
expirationDate=year;
else
expirationDate=expirationDate+"/"+year;
}
public String getMonth() {
return "";
}
public String getYear() {
return "";
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCardNumber() {
if (cardNumber == null)
cardNumber = firstFourDigit + secondFourDigit + thirdFourDigit
+ lastFourDigits;
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSecurityCode() {
return securityCode;
}
public void setSecurityCode(String securityCode) {
this.securityCode = securityCode;
}
public String getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(String expirationDate) {
this.expirationDate = expirationDate;
}
public String getFirstFourDigit() {
return firstFourDigit;
}
public String getSecondFourDigit() {
return secondFourDigit;
}
public String getThirdFourDigit() {
return thirdFourDigit;
}
public String getLastFourDigits() {
return lastFourDigits;
}
public void setLastFourDigits(String lastFourDigits) {
this.lastFourDigits = lastFourDigits;
}
public void setFirstFourDigit(String firstFourDigit) {
this.firstFourDigit = firstFourDigit;
}
public void setSecondFourDigit(String secondFourDigit) {
this.secondFourDigit = secondFourDigit;
}
public void setThirdFourDigit(String thirdFourDigit) {
this.thirdFourDigit = thirdFourDigit;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
}
public void setMonth(String month){
// ...
}
public void setYear(String year){
// ...
}
Are the problem here. Because during introspection spring looks for a field with name being name of the setXXX, without set.
see FormatAnnotationIntrospector source code
EDIT (proposed solution):
public class CreditCard {
public static class ExpirationDate {
private String month;
private String year;
// getters, setter
#Override
public String toString() {
return month + "/" + year;
}
}
private String type;
private String cardNumber;
private String name;
private String securityCode;
private ExpirationDate expirationDate;
private String firstFourDigit;
private String secondFourDigit;
private String thirdFourDigit;
private String lastFourDigits;
private String zipCode;
public void setExpirationDate(ExpirationDate expDate){
this.expirationDate = expDate;
}
public ExpirationDate getExpirationDate(){
return this.expirationDate;
}
// other getters, setters
}