Hey guys I have retrofit successfully getting data from a rest API and its printing into the log. However when I try and capture this response into an array list I'm getting an error stating : "Cannot infer arguments (unable to resolve constructor). This error shows in the array list brackets <>
// Executes the network request on a background thread
try {
Response response = getWeather(locationCode, apiKey).execute();
if (cancelRequest) {
return;
}
if (response.code() == 200) {
// Weather weather = response.body().getWeather();
Log.d(TAG, "onResponse: " + response.body().toString());
List<Weather> list = new ArrayList<>(((Weather)response.body()));
//mWeather.postValue(response);
GSON Response
{
"coord": {
"lon": -5.93,
"lat": 54.58
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}
],
"base": "stations",
"main": {
"temp": 291.56,
"feels_like": 286.36,
"temp_min": 291.15,
"temp_max": 292.15,
"pressure": 1024,
"humidity": 45
},
If anyone could help me root cause this it would be greatly appreciated.
I feel the POJO Class which you have created might not be proper as you have not shared your POJO class please try the below POJO class in your code an see if the error still persists.
public class Weather {
private coordinate coord;
private ArrayList<weatherinfo> weather;
private String base;
private maininfo main;
public coordinate getCoord() {
return coord;
}
public ArrayList<weatherinfo> getWeather() {
return weather;
}
public String getBase() {
return base;
}
public maininfo getMain() {
return main;
}
public static class coordinate{
String lon,lat;
public String getLon() {
return lon;
}
public String getLat() {
return lat;
}
}
public static class weatherinfo{
String id,main,description,icon;
public String getId() {
return id;
}
public String getMain() {
return main;
}
public String getDescription() {
return description;
}
public String getIcon() {
return icon;
}
}
public static class maininfo{
String temp,feels_like,temp_min,temp_max,pressure,humidity;
public String getTemp() {
return temp;
}
public String getFeels_like() {
return feels_like;
}
public String getTemp_min() {
return temp_min;
}
public String getTemp_max() {
return temp_max;
}
public String getPressure() {
return pressure;
}
public String getHumidity() {
return humidity;
}
}
}
After that while reading your response try it this way.
ArrayList<Weather.weatherinfo> list = response.body().getWeather();
Happy Coding
To convert the response to a usable java object, you will have to use Gson or use Retrofit to do it automatically. Since you are getting the generic Response from the call, it means you will have to do it yourself. So first convert the json schema to a POJO then instead of
List<Weather> list = new ArrayList<>(((Weather)response.body()));
use
ResponsePojo responsePojo = gson.fromJson(response.body().toString(), ResponsePojo.class);
However, instead of doing it manually, you should set up Retrofit correctly so that it does the conversion for you. Then you will get back your object directly from the retrofit call -
Response<ResponsePojo> response = getWeather(locationCode, apiKey).execute();
ResponsePojo responsePojo = response.body()
Related
This question already has answers here:
How to get List<String> from JSON list using Retrofit 2?
(2 answers)
Closed 2 years ago.
I'm trying to get some data from JSON below using Retrofit:
[
{
"country": "China",
"cases": 80650,
"todayCases": 98,
"deaths": 3070,
"todayDeaths": 28,
"recovered": 55402,
"critical": 5737
},
{
"country": "S. Korea",
"cases": 6593,
"todayCases": 309,
"deaths": 43,
"todayDeaths": 1,
"recovered": 135,
"critical": 52
}
....
]
I've tried the below code without success :
Interface :
public interface CoronaInterface {
#GET("all")
public Call<Resume> getCoronaVirusResumeInformation();
#GET("countries")
public Call<Complete> getCoronaVirusCompleteInformation();
}
Models
public class Data {
#SerializedName("country")
private String country;
#SerializedName("recovered")
private String recovered;
#SerializedName("cases")
private String cases;
#SerializedName("critical")
private String critical;
#SerializedName("deaths")
private String deaths;
#SerializedName("todayCases")
private String todayCases;
#SerializedName("todayDeaths")
private String todayDeaths;
public String getCountry() {
return country;
}
public String getRecovered() {
return recovered;
}
public String getCases() {
return cases;
}
public String getCritical() {
return critical;
}
public String getDeaths() {
return deaths;
}
public String getTodayCases() {
return todayCases;
}
public String getTodayDeaths() {
return todayDeaths;
}
}
public class Complete {
private Data[] mData;
public Data[] getData() {
return mData;
}
public void setData(Data[] mData) {
this.mData = mData;
}
}
MainActivity :
mCallComplete = mCoronaInterface.getCoronaVirusCompleteInformation();
mCallComplete.enqueue(new Callback<Complete>() {
#Override
public void onResponse(#NonNull Call<Complete> call, #NonNull Response<Complete> response) {
}
#Override
public void onFailure(#NonNull Call<Complete> call, #NonNull Throwable t) {
Toast.makeText(MainActivity.this, "ops", Toast.LENGTH_SHORT).show();
}
});
My issue: I always get ops message at runtime.
Show Retrofit object. Did you test your api using for example Postman program? is it working?
Replace "ops" with t.toString() to see the details of what caused the error. As mentioned, you need to provide source of the API.
I have a basic SpringBoot 2.1.5.RELEASE app. Using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file with some RestControllers.
In 1 of the controller this is the body I send:
{
"depositHotel": "xxx",
"destinationHotel": "aaa",
"depositHotelAmount": "0.2",
"destinationHotelAmount": "4",
"destinationAddress": [{
"address": "asdf",
"tag": ""
}],
"refundAddress": [{
"address": "pio",
"tag": ""
}]
}
so I create this class to use it as a RequestBody:
public class HotelswitchHotelOrderRequestBody {
public static class Builder {
private String depositHotel;
private String destinationHotel;
private Float depositHotelAmount;
private Float destinationHotelAmount;
private JSONObject destinationAddress;
private JSONObject refundAddress;
public Builder(String depositHotel, String destinationHotel) {
this.depositHotel = depositHotel;
this.destinationHotel = destinationHotel;
}
public Builder withDepositHotelAmount (Float depositHotelAmount) {
this.depositHotelAmount = depositHotelAmount;
return this;
}
public Builder withDestinationHotelAmount (Float destinationHotelAmount) {
this.destinationHotelAmount = destinationHotelAmount;
return this;
}
public Builder toDestinationAddress (JSONObject destinationAddress) {
this.destinationAddress = destinationAddress;
return this;
}
public Builder toRefundAddress (JSONObject refundAddress) {
this.refundAddress = refundAddress;
return this;
}
public HotelswitchHotelOrderRequestBody build(){
HotelswitchHotelOrderRequestBody order = new HotelswitchHotelOrderRequestBody();
order.depositHotel = this.depositHotel;
order.depositHotelAmount = this.depositHotelAmount;
order.destinationAddress = this.destinationAddress;
order.destinationHotel = this.destinationHotel;
order.destinationHotelAmount = this.destinationHotelAmount;
order.refundAddress = this.refundAddress;
return order;
}
}
private String depositHotel;
private String destinationHotel;
private Float depositHotelAmount;
private Float destinationHotelAmount;
private JSONObject destinationAddress;
private JSONObject refundAddress;
private HotelswitchHotelOrderRequestBody () {
//Constructor is now private.
}
public String getDepositHotel() {
return depositHotel;
}
public void setDepositHotel(String depositHotel) {
this.depositHotel = depositHotel;
}
public String getDestinationHotel() {
return destinationHotel;
}
public void setDestinationHotel(String destinationHotel) {
this.destinationHotel = destinationHotel;
}
public Float getDepositHotelAmount() {
return depositHotelAmount;
}
public void setDepositHotelAmount(Float depositHotelAmount) {
this.depositHotelAmount = depositHotelAmount;
}
public Float getDestinationHotelAmount() {
return destinationHotelAmount;
}
public void setDestinationHotelAmount(Float destinationHotelAmount) {
this.destinationHotelAmount = destinationHotelAmount;
}
public JSONObject getDestinationAddress() {
return destinationAddress;
}
public void setDestinationAddress(JSONObject destinationAddress) {
this.destinationAddress = destinationAddress;
}
public JSONObject getRefundAddress() {
return refundAddress;
}
public void setRefundAddress(JSONObject refundAddress) {
this.refundAddress = refundAddress;
}
}
But I have this error when receiving the object:
JSON parse error: out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `org.json.JSONObject` out of START_ARRAY token
JSONObject's representation in actual JSON is a hash i.e. {...}. In your json data you're providing an array of hashes [{...}] which is not the same. Judging from your domain I don't think it has to be multiple values, so you can just omit [] in your payload and if it does then the fields in your Java class can be defined as JSONArray.
However, I think you should go with defining an Address class and either using
private Address destinationAddress;
private Address refundAddress;
or if it indeed does have to be an object array
private List<Address> destinationAddresses;
private List<Address> refundAddresses;
I had a similar usecase , where I could not define the json to a POJO. Using com.fasterxml.jackson.databind.JsonNode instead of the JSONObject worked.
I am consuming a restful API which gives me the following response on a service call,
[
{
id=123,
cloudStatusTimestamp=2019-01-21T15:45:06.823,
cloudStatusCode=null,
cloudStatusMessage=300: PDF generated successfully,
cloudStatusComments=Inbound invoice,Reference: 123
}
,{
id=436,
cloudStatusTimestamp=2019-02-21T05:45:06.423,
cloudStatusCode=null,
cloudStatusMessage=300: PDF generated successfully,
cloudStatusComments=Inbound invoice, Reference: 456
}
]
I want to parse the above response to Java object. I manually tried to convert the response to JSON by replacing '=' by ':'and enclosing key and value pairs with quotes but it didn't work because some values are having ',' in between (cloudStatusComments=Inbound invoice, Reference: 456). Please share your comments.
The format of the JSON is not correct.
the format should be like this :
[
{
"id":123,
"cloudStatusTimestamp":"2019-01-21T15:45:06.823",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice",
"Reference": 123
},
{
"id":436,
"cloudStatusTimestamp":"2019-02-21T05:45:06.423",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice, Reference: 456"
}
]
hope this helps you out
Fisrt of all your json is incorrect, it should be in this format.
[
{
"id":123,
"cloudStatusTimestamp" : "2019-01-21T15:45:06.823",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice",
"Reference": 123
}
,{
"id":436,
"cloudStatusTimestamp":"2019-02-21T05:45:06.423",
"cloudStatusCode":null,
"cloudStatusMessage":"300: PDF generated successfully",
"cloudStatusComments":"Inbound invoice",
"Reference": 456
}
]
Now to parse this json, create following model class and get whatever field you want.
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Example {
#SerializedName("id")
#Expose
private Integer id;
#SerializedName("cloudStatusTimestamp")
#Expose
private String cloudStatusTimestamp;
#SerializedName("cloudStatusCode")
#Expose
private Object cloudStatusCode;
#SerializedName("cloudStatusMessage")
#Expose
private String cloudStatusMessage;
#SerializedName("cloudStatusComments")
#Expose
private String cloudStatusComments;
#SerializedName("Reference")
#Expose
private Integer reference;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCloudStatusTimestamp() {
return cloudStatusTimestamp;
}
public void setCloudStatusTimestamp(String cloudStatusTimestamp) {
this.cloudStatusTimestamp = cloudStatusTimestamp;
}
public Object getCloudStatusCode() {
return cloudStatusCode;
}
public void setCloudStatusCode(Object cloudStatusCode) {
this.cloudStatusCode = cloudStatusCode;
}
public String getCloudStatusMessage() {
return cloudStatusMessage;
}
public void setCloudStatusMessage(String cloudStatusMessage) {
this.cloudStatusMessage = cloudStatusMessage;
}
public String getCloudStatusComments() {
return cloudStatusComments;
}
public void setCloudStatusComments(String cloudStatusComments) {
this.cloudStatusComments = cloudStatusComments;
}
public Integer getReference() {
return reference;
}
public void setReference(Integer reference) {
this.reference = reference;
}
}
My Use case is I have a json file but I have to share only few of them to client.
Ex: Consider the source json file as shown below.
{
"name": "XYZ",
"age": 24,
"education": {
"college": "ppppp",
"study": "b.tech",
"grade": 6.8
},
"friends": ["kkkk",
"bbbbbbbbbbb",
"jjjjjj"],
"dob":"01-08-1990"
}
For client 1 I have to share below output
{
"personalInfo": {
"name": "XYZ",
"age": 24,
"friendsNames": ["kkkk","bbbbbbbbbbb","jjjjjj"]
},
"educationalInfo": {
"college": "ppppp",
"study": "b.tech",
"grade": 6.8
}
}
For client 2 I have to share below output
{
"personalInformation": {
"nameOfEmployee": "XYZ",
"ageOfEmployee": 24
},
"educationalInformation": {
"college": "ppppp",
"study": "b.tech"
}
}
And for other clients also the use case is same, I have to skip some keys and give different names to the keys. How to dynamically do this by some kind of configuration. I used jsonPath to achieve this but removing few keys from json object is difficult. Any suggestions can be appreciated.
Use a JSON Path library, like JayWay. With that, templates to transform your exapmle would be:
Client 1
{
"personalInfo": {
"name": "$.name",
"age": "$.age",
"friendsNames": "$.friends"
},
"educationalInfo": "$.education"
}
Client 2
{
"personalInformation": {
"nameOfEmployee": "$.name",
"ageOfEmployee": "$.age"
},
"educationalInformation": {
"college": "$.education.college",
"study": "$.education.study"
}
}
What you need to implement is the template traversal. It's about 20 lines of code; or 40 if you also need to transform list elements, like:
{
"friends": [ "$.friends[?(# =~ /.{5,}/)]", {
"name": "#",
"since": "$.dob"
} ]
}
which would result into:
{
"friends": [ {
"name": "bbbbbbbbbbb",
"since": "01-08-1990"
}, {
"name": "jjjjjj",
"since": "01-08-1990"
} ]
}
You can use Jackson to serialize and deserialize json. I suggest you to create seperate classes which represents your client data.
I show you an example of how you can deserialize your data and map it to your client json.
You can generate corresponding classes for client 2 with getting some help from http://www.jsonschema2pojo.org/ for mapping json to pojo.
Here is the code :
public class Main {
public static void main(String[] args) throws ParseException, ParserConfigurationException, IOException, SAXException {
ObjectMapper mapper = new ObjectMapper();
Root root = mapper.readValue(new File("test.json"), Root.class);
Client1 c1 = new Client1();
PersonalInfo personalInfo1 = new PersonalInfo();
personalInfo1.setAge(root.getAge());
personalInfo1.setFriendsNames(root.getFriends());
personalInfo1.setName(root.getName());
EducationalInfo educationalInfo1 = new EducationalInfo();
educationalInfo1.setCollege(root.getEducation().getCollege());
educationalInfo1.setGrade(root.getEducation().getGrade());
educationalInfo1.setStudy(root.getEducation().getStudy());
c1.setPersonalInfo(personalInfo1);
c1.setEducationalInfo(educationalInfo1);
mapper.writeValue(new File("client1.json"), c1);
}
}
Inside test.json file :
{
"name": "XYZ",
"age": 24,
"education": {
"college": "ppppp",
"study": "b.tech",
"grade": 6.8
},
"friends": [
"kkkk",
"bbbbbbbbbbb",
"jjjjjj"
],
"dob": "01-08-1990"
}
Inside client1.json file :
{
"personalInfo": {
"name": "XYZ",
"age": 24,
"friendsNames": [
"kkkk",
"bbbbbbbbbbb",
"jjjjjj"
]
},
"educationalInfo": {
"college": "ppppp",
"study": "b.tech",
"grade": 6.8
}
}
Here is the classes which represents your json data:
class Education {
private String college;
private String study;
private float grade;
public String getCollege() {
return college;
}
public void setCollege(String college) {
this.college = college;
}
public String getStudy() {
return study;
}
public void setStudy(String study) {
this.study = study;
}
public float getGrade() {
return grade;
}
public void setGrade(float grade) {
this.grade = grade;
}
}
// root of your base json data
class Root {
private String name;
private int age;
private Education education;
private List<String> friends;
private String dob;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Education getEducation() {
return education;
}
public void setEducation(Education education) {
this.education = education;
}
public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
public String getDob() {
return dob;
}
public void setDob(String dob) {
this.dob = dob;
}
}
class EducationalInfo {
private String college;
private String study;
private float grade;
public String getCollege() {
return college;
}
public void setCollege(String college) {
this.college = college;
}
public String getStudy() {
return study;
}
public void setStudy(String study) {
this.study = study;
}
public float getGrade() {
return grade;
}
public void setGrade(float grade) {
this.grade = grade;
}
}
// class which represents client 1 json data
class Client1 {
private PersonalInfo personalInfo;
private EducationalInfo educationalInfo;
public PersonalInfo getPersonalInfo() {
return personalInfo;
}
public void setPersonalInfo(PersonalInfo personalInfo) {
this.personalInfo = personalInfo;
}
public EducationalInfo getEducationalInfo() {
return educationalInfo;
}
public void setEducationalInfo(EducationalInfo educationalInfo) {
this.educationalInfo = educationalInfo;
}
}
class PersonalInfo {
private String name;
private int age;
private List<String> friendsNames = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getFriendsNames() {
return friendsNames;
}
public void setFriendsNames(List<String> friendsNames) {
this.friendsNames = friendsNames;
}
}
What about converting it to XML then create some XSLT? it might be much readable and cleaner.
I push full worked example in java into GIT with libs (lombok and jackson)
Template json mapped to object and object to json with different clients.
Your job is to output multilevel JSON data as multiple JSON formats. JSONPath can do this but the process is a hassle.
A simple alternative is to use SPL. SPL is a Java open-source package. You just need three lines of code to get the job done:
enter image description here
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as jsonparse.splx and invoke it in a Java application as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call jsonparse()");
st.execute();
…
Java doesn't have great templating built in.
But if you want to do a quick an dirty JSON template where you can replace a few values -- especially without all that ugly quote escaping:
{"key":"value"}
You can use single quotes and string replace:
{'key':'VALUE'}.replace("'", """).replace("VALUE", 42)
A few caveats:
This will break if any existing keys or values have single quotes (like O'malley).
It won't replace strings with numbers, boolean, or null
It can't -- by itself -- insert nested arrays or objects (e.g. [] {}) other than as strings.
But with a little bit of of extra work, you can accomplish the 80/20 rule. After that point you'd probably want to look into parsing or generating -- but by then you're not looking for a quick template.
i want to parse Json with this format:
{"data": {
"user": {
"edge_follow": {
"count": 2554, "page_info": {
"node": {
"id": "5719761315", "username": "disneyangell" ...
"node": {
"id": "2260368333", "username": "moosa_sedaghat",...
"node": {
"id": "3982701506", "username": "alidadashi512", ...
.
.
.
from this link ;
i got my pojos from www.jsonschema2pojo.org/
i tried GsonConverter and Jackson ObjectMapper also
the problem is parsed object's node list is empty or it's zero always.
how to solve this?
if i need to use CustomConverter write that for this case.
So to get the JSON you want you have to be logged in to instagiam. Otherwise you will get an empty "edges" object in the JSON returned from your get request. If you are logged in here is an example to do it with Gson:
The POJO (maybe you need to add getter methods for fields you are interested in):
public class FollowJson{
Data data;
String status;
public ArrayList<FollowNode> getFollowNodes(){
return data.getFollowNodes();
}
class Data{
User user;
public ArrayList<FollowNode> getFollowNodes(){
return user.getFollowNodes();
}
}
class User{
EdgeFollow edge_follow;
public ArrayList<FollowNode> getFollowNodes(){
return edge_follow.getFollowNodes();
}
}
class EdgeFollow{
Integer count;
ArrayList<OuterNode> edges;
HashMap<String, Object> page_info;
public ArrayList<FollowNode> getFollowNodes(){
ArrayList<FollowNode> bufList = new ArrayList<FollowNode>();
for(OuterNode outer : edges){
bufList.add(outer.getNode());
}
return bufList;
}
}
class OuterNode{
FollowNode node;
public FollowNode getNode(){
return node;
}
}
class FollowNode {
Boolean followed_by_viewer;
String full_name;
String id;
Boolean is_verified;
String profile_pic_url;
Boolean requested_by_viewer;
String username;
public Boolean getFollowedStatus(){
return followed_by_user;
}
public String getId(){
return id;
}
public String getUsername(){
return username;
}
}
}
Then pass the POJO.class and the JSON string to the Method:
public <T> T getJsonFromString(String jsonString, Class<T> var){
GsonBuilder builder = new GsonBuilder();
return builder.create().fromJson(jsonString, var);
}
You can then call getFollowNodes() on the returned object, which returns an array of objects (FollowNode) representing the "nodes" in the JSON.