Retrofit parsing JSON response null values Android - java

Hi i cant work out why I am getting null values for my response. Im using Retrofit library on Android.
raw json
{
"images": [
{
"image": {
"name": "nike adver",
"url": "http:\/\/wallpaperbarcelona.com\/wp-content\/uploads\/2013\/07\/neymar-nike-advert.jpg",
"type": "photo"
}
}]
}
// interface
public interface PromoImagesAPI {
#GET("/FriendsCMS/images/?type=photo&format=json")
void promoImages(Callback<ImagesObject> callback);
}
request function
private void requestNewsData(String uri) {
RestAdapter api = new RestAdapter.Builder().setEndpoint(ENDPOINT).build();
PromoImagesAPI restapi = api.create(PromoImagesAPI.class);
restapi.promoImages(new Callback<Images>() {
#Override
public void success(Images imageObjects, Response response) {
System.out.println("webservice " +response.getUrl());
for (int i = 0; i < imageObjects.images.size(); i++) {
System.out.println("webservice " +imageObjects.getImages().get(i).getUrl());
}
}
#Override
public void failure(RetrofitError error) {
System.out.println("webservice " + error);
}
});
}
Pojo
public class ImagesObject {
public List<Images> images;
public class Images {
public String name;
public String url;
public String type;
public String getName() {
return name;
}
public String getUrl() {
return url;
}
public String getType() {
return type;
}
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public void setType(String type) {
this.type = type;
}
}
}
The thing is the amount of elements in the for loop is correct, i have tested that, the values are all null. Have i missed something, any help would be gratefully appreciated . thanks

use http://www.jsonschema2pojo.org/ to create your java object model and do the following to call
public interface PromoImagesAPI {
#GET("/FriendsCMS/images/?type=photo&format=json")
void promoImages(Callback<Images> callback);

Yes, I answer by agreeing. I also missed the #Expose annotation. This can happen specially when using third party tools to convert from json to kotlin or java classes. I also used Gson to convert from json when doing unit testing and everything was passing gracefully until I ran the app and everything came back with null values

Related

How to solve E/error: End of input at line 1 column 1 path $ in android studio

When I try to call rest API in the android studio I get an error that:
E/error: End of input at line 1 column 1 path $
I use firebase for the database and retrofit2 library.
But when I call the values a go to the firebase database and call the onFailure in call.enqueue() method.
public class APis {
public static final String URL = "http://192.168.178.43:8081/api/";
public static userService setuser() {
return client.getClient(URL).create(userService.class);
}
}
public interface userService {
#Headers("Content-Type: application/json")
#POST("signup")
Call<userlog> adduser(#Body userlog userlog);
}
public class userlog {
#SerializedName("email")
#Expose
private String emial_;
#SerializedName("password")
#Expose
private String password_;
#SerializedName("name")
#Expose
private String name_;
public userlog() {
}
public userlog(String emial_, String password, String name_) {
this.emial_ = emial_;
this.password_ = password;
this.name_ = name_;
}
public String getEmial_() {
return emial_;
}
public void setEmial_(String emial_) {
this.emial_ = emial_;
}
public String getPassword_() {
return password_;
}
public void setPassword_(String password_) {
this.password_ = password_;
}
public String getName_() {
return name_;
}
public void setName_(String name_) {
this.name_ = name_;
}
}
public void setPassword_(String password_) {
this.password_ = password_;
}
}
private void adduser_(userlog userll) {
service = APis.setuser();
Call<userlog> call = service.adduser(userll);
call.enqueue(new Callback<userlog>() {
#Override
public void onResponse(Call<userlog> call, Response<userlog> response) {
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
/* userdetails.setUserid(firebaseAuth.getUid());
userdetails.setEmail_(emailId.getText().toString());
startActivity(new Intent(SignupActivity.this, MainnewActivity.class));*/
}
}
#Override
public void onFailure(Call<userlog> call, Throwable t) {
Log.e("error", t.getMessage());
Toast.makeText(getApplicationContext(), "not Successdd", Toast.LENGTH_SHORT).show();
}
});
}
when I call "adduser_(userll)" method, I get a notification that "not Successdd".
The problem related to retrofit, i think the problem because the response of the call come as null or empty
you can create NullConverterFactory.class :
public class NullConverterFactory extends Converter.Factory {
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
#Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
and add to the create of the retrofit
baseUrl(Config.URL+"/")
.client(okHttpClient)
// -----add here-------
.addConverterFactory(new NullConverterFactory())
//---------------------
.addConverterFactory(GsonConverterFactory.create())
.build()

Could not read JSON: Can not construct instance from String value

I have pojo class Ticket
public class Ticket implements Serializable{
#JsonProperty("lineItemStatus")
private String revisionStatus;
public String getRevisionStatus() {
return revisionStatus;
}
public void setRevisionStatus(String revisionStatus) {
this.revisionStatus = revisionStatus;
}
public void setRevisionStatus(RevisionStatus revisionStatus) {
String status = "";
if (revisionStatus != null) {
switch (revisionStatus) {
case added: {
status = "New";
break;
}
case updated: {
status = "Modified";
break;
}
}
}
this.revisionStatus = status;
}
}
Also I have an enum
public enum RevisionStatus {
added {
#Override
public String getName() {
return this.name();
}
},
updated {
#Override
public String getName() {
return this.name();
}
}
public abstract String getName();
}
During GET request , I use setRevisionStatus(RevisionStatus revisionStatus) method and i get response like for example
{"lineItemStatus": "Modified"} which is fine
But problem occurs during PUT request . During PUT request, my requirement is that I should be able to send payloads like for {"lineItemStatus": "Modified"} or {"lineItemStatus": "New"} or {"lineItemStatus": "abc"} , meaning lineItemStatus should be able to accept any String value . I am using #RequestBody Ticket ticket for receiving the payload.
The debugger doesn't come inside the controller and fails at the payload step . How do I handle this error without making any changes inside Enum ?
You can do it by updating your enum:
public enum RevisionStatus {
added("New") {
#Override
public String getName() {
return this.name();
}
},
updated("Modified") {
#Override
public String getName() {
return this.name();
}
};
private String status;
private RevisionStatus(String status) {
this.status = status;
}
public abstract String getName();
/**
* #return the status
*/
public String getStatus() {
return status;
}
#JsonCreator
public static RevisionStatus fromValue(String text) {
if(StringUtils.isNoneBlank(text)) {
for (RevisionStatus b : RevisionStatus.values()) {
if (String.valueOf(b.toString()).equalsIgnoreCase(text.trim())) {
return b;
}
}
}
return null;
}
}
Here we have updated enum to value enum. And fromValue() method with #JsonCreator annotation will bind this String value with the Enum constant.
Additionally this way you won't need that switch cases during get method. As getStatus() method will give you the status value directly. And that will improve your code design also.
Just an additional point here, I don't see any need of this getName() method, as the placed where getName() is called, directly name() can be called. As that is also a public method.

Retrofit expecting an array not an object

Hi I am new to the Retrofit 2.0 library, I am having problems parsing some json. I have looked at some other solutions on Stackoverflow but not having much luck with my problem. I am trying to call an api from android with retrofit 2.0.But it is throwing error Expected BEGIN_ARRAY but was BEGIN_OBJECT.
Any ideas what im doing wrong?
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 2 column 2 path $
Fragment.java
ListView superListView;
static Retrofit retrofit = null;
#Override
public void onCreate (#Nullable Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
connect2();
}
private void connect2() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
HomeApiService movieApiService = retrofit.create(HomeApiService.class);
Call<List<Movie3>> call = movieApiService.popularMovies2();
call.enqueue(new Callback<List<Movie3>>() {
#Override
public void onResponse(Call<List<Movie3>> call, Response<List<Movie3>> response) {
List<Movie3> myheroList2 = response.body();
String[] oneHeroes = new String[myheroList2.size()];
for (int i2 = 0; i2 < myheroList2.size(); i2++) {
oneHeroes[i2] = myheroList2.get(i2).getTitle();
}
superListView.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_list_item_2, oneHeroes));
}
#Override
public void onFailure(Call<List<Movie3>> call, Throwable throwable) {
Log.e("Error: ", throwable.toString());
}
});
}
HomeApiService.java
public interface HomeApiService {
#GET("movie/test")
Call<List<Movie3>> popularMovies2 ();
}
Movie3.java
public class Movie3 {
#SerializedName("title")
private String title;
public Movie3(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
Ok...First of all your POJO for accepting the response is not correct. This is a crucial part while accepting a response. Your POJO should look like this :
public class Result{
public boolean adult;
public String backdrop_path;
public List<int> genre_ids;
public int id;
public String original_language;
public String original_title;
public String overview;
public double popularity;
public String poster_path;
public String release_date;
public String title;
public boolean video;
public double vote_average;
public int vote_count;
}
public class Root{
public int page;
public List<Result> results;
public int total_pages;
public int total_results;
}
Where root is the class and result is another class. As you can see the response contains result as a list.
And also the HomeApiService should look like this:
public interface HomeApiService {
#GET("movie/popular?api_key=ffd597419be5a256066dc51c49bc659f")
Call<Root> popularMovies2 ();
}
Hope you got the point. Add necessary getters and setters. Normally it's easy to use a JSON to POJO online converter. Here is one: https://json2csharp.com/json-to-pojo ..... paste the response in JSON and get the POJO converted.

How to Parse nested json using Retrofit?

I want to parse nested json using retrofit and bind it in recyclerview. Am familiar with Parsing simple json using Retrofit. But i dont know how to parse nested json using retrofit. i am newbie to retrofit. any help will be appreciated ?
Here is that Link: http://api.wunderground.com/api/356d60036a9374e9/conditions/forecast/alert/q/22.897,88.879.json
JSON DATA :
{
"response": {
"version":"0.1",
"termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
"features": {
"conditions": 1
,
"forecast": 1
}
,
"error": {
"type": "unknownfeature"
}
}
, "current_observation": {
"image": {
"url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
"title":"Weather Underground",
"link":"http://www.wunderground.com"
},
"display_location": {
"full":"Tentulbaria, India",
"city":"Tentulbaria",
"state":"WB",
"state_name":"India",
"country":"IN",
"country_iso3166":"IN",
"zip":"00000",
"magic":"608",
"wmo":"41946",
"latitude":"22.890000",
"longitude":"88.870000",
"elevation":"11.9"
},
"observation_location": {
"full":"Kolkata, ",
"city":"Kolkata",
"state":"",
"country":"IN",
"country_iso3166":"IN",
"latitude":"22.64999962",
"longitude":"88.44999695",
"elevation":"20 ft"
},
"estimated": {
},
"station_id":"VECC",
"observation_time":"Last Updated on February 5, 5:30 PM IST",
"observation_time_rfc822":"Mon, 05 Feb 2018 17:30:00 +0530",
"observation_epoch":"1517832000",
"local_time_rfc822":"Mon, 05 Feb 2018 17:44:32 +0530",
"local_epoch":"1517832872",
"local_tz_short":"IST",
"local_tz_long":"Asia/Kolkata",
"local_tz_offset":"+0530",
"weather":"Clear",
"temperature_string":"81 F (27 C)",
"temp_f":81,
"temp_c":27,
"relative_humidity":"61%",
"wind_string":"Calm",
"wind_dir":"North",
"wind_degrees":0,
"wind_mph":0,
"wind_gust_mph":0,
"wind_kph":0,
"wind_gust_kph":0,
"pressure_mb":"1013",
"pressure_in":"29.92",
"pressure_trend":"0",
"dewpoint_string":"66 F (19 C)",
"dewpoint_f":66,
"dewpoint_c":19,
"heat_index_string":"83 F (28 C)",
"heat_index_f":83,
"heat_index_c":28,
"windchill_string":"NA",
"windchill_f":"NA",
"windchill_c":"NA",
"feelslike_string":"83 F (28 C)",
"feelslike_f":"83",
"feelslike_c":"28",
"visibility_mi":"1.7",
"visibility_km":"2.8",
"solarradiation":"--",
"UV":"-1","precip_1hr_string":"-9999.00 in (-9999.00 mm)",
"precip_1hr_in":"-9999.00",
"precip_1hr_metric":"--",
"precip_today_string":"0.00 in (0.0 mm)",
"precip_today_in":"0.00",
"precip_today_metric":"0.0",
"icon":"clear",
"icon_url":"http://icons.wxug.com/i/c/k/nt_clear.gif",
"forecast_url":"http://www.wunderground.com/global/stations/41946.html",
"history_url":"http://www.wunderground.com/history/airport/VECC/2018/2/5/DailyHistory.html",
"ob_url":"http://www.wunderground.com/cgi-bin/findweather/getForecast?query=22.64999962,88.44999695",
"nowcast":""
}
}
In that json data i want to fetch the following json data:
"current_observation": {
"image": {
"url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
"title":"Weather Underground",
"link":"http://www.wunderground.com"
},
First, create Model i.e POJO class to parse your response
It will look something like this
package app.com.socket;
/**
* Created by akshay.katariya on 05-Feb-18.
*/
import com.google.gson.annotations.SerializedName;
public class Pojo
{
#SerializedName("response")
public Response response;
#SerializedName("current_observation")
public Current_observation current_observation;
public static class Features {
#SerializedName("conditions")
public int conditions;
#SerializedName("forecast")
public int forecast;
}
public static class Error {
#SerializedName("type")
public String type;
}
public static class Response {
#SerializedName("version")
public String version;
#SerializedName("termsofService")
public String termsofService;
#SerializedName("features")
public Features features;
#SerializedName("error")
public java.lang.Error error;
}
public static class Image {
#SerializedName("url")
public String url;
#SerializedName("title")
public String title;
#SerializedName("link")
public String link;
}
public static class Display_location {
#SerializedName("full")
public String full;
#SerializedName("elevation")
public String elevation;
}
public static class Observation_location {
#SerializedName("elevation")
public String elevation;
}
public static class Estimated {
}
public static class Current_observation {
#SerializedName("image")
public Image image;
#SerializedName("display_location")
public Display_location display_location;
#SerializedName("observation_location")
public Observation_location observation_location;
#SerializedName("estimated")
public Estimated estimated;
#SerializedName("nowcast")
public String nowcast;
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public Display_location getDisplay_location() {
return display_location;
}
public void setDisplay_location(Display_location display_location) {
this.display_location = display_location;
}
public Observation_location getObservation_location() {
return observation_location;
}
public void setObservation_location(Observation_location observation_location) {
this.observation_location = observation_location;
}
public Estimated getEstimated() {
return estimated;
}
public void setEstimated(Estimated estimated) {
this.estimated = estimated;
}
public String getNowcast() {
return nowcast;
}
public void setNowcast(String nowcast) {
this.nowcast = nowcast;
}
}
public Response getResponse() {
return response;
}
public void setResponse(Response response) {
this.response = response;
}
public Current_observation getCurrent_observation() {
return current_observation;
}
public void setCurrent_observation(Current_observation current_observation) {
this.current_observation = current_observation;
}
}
Generate proper getter & setter
Then in your main class create
Pojo model = new Pojo();
Call API & Parse the response
model = response.body(); // retrofit api call parsing
You have all your values ready to set
mEditText.setText(model.getCurrent_observation().image.url);
You can add json convertor to Retrofit and you can parse it.
Parsing Nested Json
Retrofit best tutorial i have found till now.
Retrofit complete turoial.
This will help you in all your concerns related to Retrofit.
Create mode like this and in your response type pass the model it will automatically parse the json into model for image data
public class Example {
#SerializedName("current_observation")
#Expose
private CurrentObservation currentObservation;
public CurrentObservation getCurrentObservation() {
return currentObservation;
}
public void setCurrentObservation(CurrentObservation currentObservation) {
this.currentObservation = currentObservation;
}
public static class CurrentObservation {
#SerializedName("image")
#Expose
private Image image;
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
public static class Image {
#SerializedName("url")
#Expose
private String url;
#SerializedName("title")
#Expose
private String title;
#SerializedName("link")
#Expose
private String link;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
}
sample api call
public interface Service {
#GET("users/info")
Call<Example> getInfo();
}
Edit:
you can call this retrofit function anywhere in your MainActivity and use the data.
public void getImageData(){
Call<Example> call = apiService.getInfo();
call.enqueue(new Callback<Example>() {
#Override
public void onResponse(Call<Example> call, Response<Example> response) {
//this is how you can use the parsed model
Example info = response.body();
}
#Override
public void onFailure(Call<Example> call, Throwable t) {
//handle the error here
}
}
Simple way is to receive response as a JsonObject / JsonArray and parse it to create object with your own Model class.
So that you can avoid unwanted data, yes your code will be lengthy but its worth it. You can format and store the data. Easy to display.
Also "Opt" methods can be used instead of "Get", so NULL can be avoided.

Convert JSON to JAVA Object through play.data.Form

I have no idea what to do with this problem.
I have a JSON object to assist in value input through POST (using Play Framework) that structures like this:
{
"start_absolute": 1403185486254,
"end_absolute": 1403185486254,
"metrics": [
{
"name": "parts",
"tags": [
{
"key":"machine",
"value":"10"
}
],
"sampling":
{
"value": 1,
"unit": "minutes"
}
}
]
}
And in server side i try to process the info like this:
Form<QueryForm> queryForm = Form.form(QueryForm.class).bindFromRequest();
if (queryForm.hasErrors()) {
return badRequest(queryForm.errorsAsJson());
}
QueryForm queryInfo = queryForm.get();
the classes used to define the JSON object in java
public class QueryForm {
private Date start_absolute;
private Date end_absolute;
private List<MetricForm> metrics= Lists.newArrayList();
public Date getStart_absolute() {
return start_absolute;
}
public void setStart_absolute(long start_absolute) {
this.start_absolute = new Date(start_absolute);
}
public Date getEnd_absolute() {
return end_absolute;
}
public void setEnd_absolute(long end_absolute) {
this.end_absolute =new Date(end_absolute);
}
public List<MetricForm> getMetrics() {
return metrics;
}
public void setMetrics(List<MetricForm> metrics) {
this.metrics = metrics;
}
#Override
public String toString() {
return "QueryForm[start_absolute="+start_absolute+", end_absolute="+end_absolute+", metrics="+metrics+"]";
}
.
public class MetricForm {
private String name;
private List<Tag> tags= Lists.newArrayList();
private RelativeTimeForm sampling= new RelativeTimeForm(1,"milliseconds");
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags.addAll(tags);
}
public RelativeTimeForm getSampling() {
return sampling;
}
public void setSampling(int val, String unit) {
this.sampling.setUnit(unit);
this.sampling.setVal(val);
}
#Override
public String toString() {
return "MetricForm[name="+name+", tags="+tags+",sampling="+sampling+"]";
}
.
public class Tag {
private String key;
private String value;
public Tag(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
return String.format(
"Tag[key=%s, value='%s']",
key, value
);
}
}
.
public class RelativeTimeForm {
private int value;
private String unit;
public RelativeTimeForm (int val, String unit){
this.setValue(val);
this.setUnit(unit);
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
#Override
public String toString() {
return "RelativeTimeForm[value="+value+", unit="+unit+"]";
}
I'm not experienced working with play.data.Form but in previous ocasions with simpler objects (Using primitive data types and String) this worked fine but when i tried to POST to the play application (Header: Content-Type = application/json; charset=utf-8) it occurs an Internal Server Error:
play.api.Application$$anon$1: Execution exception [[InvalidPropertyException:
Invalid property 'metrics[0].tags[0]' of bean class [model.QueryForm]: Illegal
attempt to get property 'tags' threw exception; nested exception is
org.springframework.beans.NullValueInNestedPathException: Invalid property
'metrics[0].tags' of bean class [model.QueryForm]: Could not instatiate property
path:
java.lang:InstatiationException: [model.Tag]
Any one can help with this? I canĀ“t figure out what to do. Is it to complex of an object to convert from JSON? Do i need to add some JSON Annotations (not currently using them)?
I have no clue how to fix this
UPDATE: I narrowed it down to the Tag class. for some reason i'm not able to instatiate Tag through JSON. I even tried setting a single Tag instance in the same level as the dates and it gives the same error (It work for Sampling)
RESOLVED:
Spring binding exception when a form is submitted
The answer is in the post above. I have to set an empty construtor in Tag class for it to work.
public Tag(){
}
The exception means, that one or more attributes aren't instantiated.
private List<MetricForm> metrics = new ...;
private List<Tag> tags = new ...;
private RelativeTimeForm sampling = new ...;
should do it.
In the case you get problems to read in your time values: Instead of using Date type directly to read in, I would use long to read in the time values and then (internally) convert them to Date objects.

Categories

Resources