I want to pass Json array with no name inside Retrofit body but I am getting 400 error.I would like to pass this json array with no name via pojo.Below is the json array that I want to pass.Also I am using PATCH method for this.
[{
"op": "replace",
"path": "/billing_address/line1",
"value": "some other value"}]
I am using following method and in this method I am getting the same response in logcat for list that I wanted but after passing it inside getAuthentionToken I am getting 400 error.
Call<JSONResponse> getAuthentionToken(#Body List obj);
JSONObject jobj = new JSONObject();
jobj.put("op","replace");
jobj.put("path","/billing_address/line1");
jobj.put("value","some other value");
List arrlist = new ArrayList();
arrlist.add(jobj);
apiInterface.getAuthentionToken(arrlist).enqueue(new Callback<JSONResponse>() {
If you are sending data over request body your implementation should be like this:
Define model according to fields (CaseSensitive "Name" -> String Name etc )
set your api function also like that
#POST("/api/geo/getLoc")
public void getFriendsLocation(#Body YourClass classObject, Callback<JsonElement> response);
Use directly your created class object on post request
getFriendsLocation(yourClassObjectThatIncludesFields, new Callback .... );
If your sending data over params You can do this with Gson.
1. Lets say you have a class that have fields like id , number and FriendNumber.Define a function :
public static Map<String, Object> getMapFromObject(Object o) {
Gson gson = new Gson();
Type stringObjectMap = new TypeToken<Map<String, Object>>() {
}.getType();
return gson.fromJson(gson.toJson(o), stringObjectMap);
}
2. set your api function also like that
#POST("/api/geo/getLoc")
public void getFriendsLocation(#QueryMap Map<String, Object>, Callback<JsonElement> response);
When you are sending post request create object from your fields call this function like below here
getFriendsLocation(getMapFromObject(yourClassObjectThatIncludesFields), new Callback .... );
I didnt write whole code which includes class definition and Callback function because they are up to your customization. I assume that you need to send over body so try the first way.
Below is the right answer for me and its work fine.
public class CardUpdate {
public String op;
public String path;
public String value;
public CardUpdate(String op, String path, String value) {
this.op = op;
this.path = path;
this.value = value;
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public String toString() {
/*return "CardUpdate{" +
"op='" + op + '\'' +
", path='" + path + '\'' +
", value='" + value + '\'' +
'}';*/
return "{" +'"'+
"op" + '"'+":" +'"' +op + '"'+
"," + '"'+"path" + '"'+":" + '"'+ path + '"'+
"," + '"'+"value" + '"'+":" + '"'+ value + '"'+
'}';
}
}
CardUpdate updatt = new CardUpdate("replace","/billing_address/line1","some other value");
List<CardUpdate> cardddd = new ArrayList<CardUpdate>();
cardddd.add(updatt);
Related
I am building an android app that displays the COVID19 statistics for India, I am getting the stats in JSON format from https://api.covid19india.org/data.json , this API contains data of individual states too,
Below is the snip of Json array(contains json objects representing each state) that i am requesting
as of Now i am displaying the entire data ( all states ) at a time on my screen, However i want to give the state name as the input and display the stats of only that state For eg. in the below image in place of sample i want to write a state name and the stats of that state must be displayed on click of the button.
Here is the code of mainActivity.java, I am using Volley Library for fetching data from API
public class MainActivity extends AppCompatActivity {
private TextView result;
private RequestQueue mq;
public String value;
int flag = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
result = findViewById(R.id.textView4);
Button parse = findViewById(R.id.button);
mq = Volley.newRequestQueue(this);
EditText text = (EditText)findViewById(R.id.state_ip);
value = text.getText().toString();
parse.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
jsonParse(value);
**//How do i pass 'value' i.e the state name entered by user to jsonParse**
}
});
}
private void jsonParse(final String value) {
Log.d("val_state",value);
String url = "https://api.covid19india.org/data.json";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("statewise");
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject st = jsonArray.getJSONObject(i);
String statename = st.getString("state");
String active = st.getString("active");
String confirmed = st.getString("confirmed");
String deaths = st.getString("deaths");
String recovered = st.getString("recovered");
if(statename.equals(value))
{
flag= 1;
}
statename = "State : " + statename;
active = "Active Cases : " + active;
confirmed = "Confirmed Cases : " + confirmed;
deaths = "Total Deaths : " + deaths;
recovered = "Total Recovered : " + recovered;
if(flag==1)
{
flag=0;
result.append(statename + "\n" + String.valueOf(active) + "\n" + String.valueOf(confirmed) + "\n" + String.valueOf(deaths) + "\n" + String.valueOf(recovered) + "\n\n\n");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
mq.add(request);
}
}
Here , i want to pass the value of state entered by the user to the method jsonParse() so that i check the state name with the received JSON data and append it to the TextView, but when i do this , and try to log the value inside the jsonParse() method i get nothing, why is this happening , How do i implement the above ?
Your EditText value is update and has to be captured after the button is clicked.
parse.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
value = text.getText().toString();
jsonParse(value);
}
});
I used retrofit to get a response from the API, but I got different types of response from the same API, like these
JsonObject
String type
Boolean Type
Based on the situation, it gives different types of responses from the same API.
I tried to use this code:
serverUtilities.getBaseClassService(getApplicationContext(), "").forgotPasswordSecurityAnswerCheck(in, new Callback<JsonObject>() {
#Override
public void success(JsonObject s, retrofit.client.Response response) {
Log.d("forgot_password_respons", "--->" + "" + s.toString());
/* to retrieve the string or integer values*/
if (s.toString().equals("5")) {
utilities.ShowAlert("selected wrong question", "Forgot Password SecQues");
}
if (s.toString().equals("1")) {
// some alert here
}
/* to retrieve the boolean values*/
if (s.toString().equals("false")) {
utilities.ShowAlert(getResources().getString(R.string.otp_fail), "Forgot Password SecQues");
}
if (s.toString().equals("1")) {
utilities.ShowAlert("Email already registered", "Social Registration");
}
/*to retrieve the Json object*/
else
if (s.toString().charAt(0) == '{') {
Log.d("my_first_char", "" + s.toString().charAt(0));
try {
if (s.toString().contains("memberId")) {
String MemberId = s.get("memberId").getAsString();
String optId = s.get("otpId").getAsString();
Log.d("Forgot_pass_ques_act", "" + MemberId + "--->" + optId);
Singleton.setSuccessId(MemberId);
Singleton.setOptId(optId);
Intent intent = new Intent(ForgotPasswordQuestionActivity.this, PasswordActivity.class);
startActivity(intent);
Toast.makeText(ForgotPasswordQuestionActivity.this, "congrats!! second step Success ", Toast.LENGTH_SHORT).show();
} else if (s.toString().contains("mId")) {
}
} catch (Exception e) {
utilities.ShowAlert(e.getMessage(), "forgot passwordQues(catch)");
Log.d("forgot_password_error", "" + e.getMessage());
}
// Singleton.setSuccessId(s);
}
}
#Override
public void failure(RetrofitError error) {
utilities.ShowAlert(error.getMessage(), "forgot passwordQues(server)");
Log.d("forgot_passwo_secAnser", "--->" + error.getMessage());
}
});
Here I kept that return type as "jsonObject" in the call back and converted in to a string and checked whether it was a JsonObject or boolean or String and perform the actions related to that.
But I got this exception while handling the responses:
Response:
com.google.gson.JsonSyntaxException:Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive
Can anyone suggest me how to handle these responses in single type of Callback in retrofit?
If I used a String type as a callback like this:
server_utilities.getBaseClassService(getApplicationContext(), "").forgotPasswordResponse(in, new Callback<String>() {
#Override
public void success(String s, retrofit.client.Response response) {
Log.d("forgot password resp", "--->" + "" + s.toString());
}
#Override
public void failure(RetrofitError error) {
Log.d("forgot_password_error", "--->" + error.getMessage());
}
});
}
I am getting this error:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 path $
The server can't give you a boolean object, and Retrofit is automatically converting a String to a JSONObject for you since that's the type you told it
To stop that, just request a string, and parse it later
new Callback<String>()
or perhaps
new Callback<JsonPrimitive>()
You can also get response.raw attribute (which is in Retrofit 2.x)
declare tag type as Object
#SerializedName("response") #Expose public Object response;
and after getting response check the type and convert to accordingly
if (response.body().response!=null && response.body().response instanceof Collection<?>) {
//if you find response type is collection then convert to json then json to real collection object
String responseStr = new Gson().toJson(data.diagnosis.provisionalDiagnosis);
Type type=new TypeToken<List<Response>>(){}.getType();
List<Response> responseList=new Gson().fromJson(responseStr,type);
if(responseList.size() > 0){
patientInfoBinding.phoneTv.setText(responseList.get(0).phnNo);
}
}else if (response.body() instanceof String){
String res=response.body();
}else {}
like above you can check instanceof String/instanceof Boolean
I got tired using this library, this is my first time using it and made a lot of success ways, but i'm a bit confused in getting the following Json :
{
"Guides":
{
"English": {"ArabicSony":"Test1","ArabicNexus":"Test2","ArabicSamsung":"Test3","ArabicHTC":"Test4"}
,"Arabic": {"EnglishSony":"Test1","EnglishNexus":"Test2","EnglishSamsung":"Test3","EnglishHTC":"Test4"}
}
}
Googled and saw a lot of guides and answered, and made my List like this :
public class PostItem {
List<PostItemArabic> Arabic;
List<PostItemEnglish> English;
}
class PostItemArabic{
private String ArabicSony;
private String ArabicNexus;
private String ArabicSamsung;
private String ArabicHTC;
public String getArabicSony() {
return ArabicSony;
}
public void setArabicSony(String arabicSony) {
ArabicSony = arabicSony;
}
public String getArabicNexus() {
return ArabicNexus;
}
public void setArabicNexus(String arabicNexus) {
ArabicNexus = arabicNexus;
}
public String getArabicSamsung() {
return ArabicSamsung;
}
public void setArabicSamsung(String arabicSamsung) {
ArabicSamsung = arabicSamsung;
}
public String getArabicHTC() {
return ArabicHTC;
}
public void setArabicHTC(String arabicHTC) {
ArabicHTC = arabicHTC;
}
}
class PostItemEnglish{
private String EnglishSony;
private String EnglishNexus;
private String EnglishSamsung;
private String EnglishHTC;
public String getEnglishSony() {
return EnglishSony;
}
public void setEnglishSony(String englishSony) {
EnglishSony = englishSony;
}
public String getEnglishNexus() {
return EnglishNexus;
}
public void setEnglishNexus(String englishNexus) {
EnglishNexus = englishNexus;
}
public String getEnglishSamsung() {
return EnglishSamsung;
}
public void setEnglishSamsung(String englishSamsung) {
EnglishSamsung = englishSamsung;
}
public String getEnglishHTC() {
return EnglishHTC;
}
public void setEnglishHTC(String englishHTC) {
EnglishHTC = englishHTC;
}
}
My Model :
private class Model {
private List<PostItem> Guides;
public List<PostItem> getGuides() {
return Guides;
}
public void setGuides(List<PostItem> roms_center) {
this.Guides = roms_center;
}
}
And printing the result like this :
List<PostItem> Guides = response.body().getGuides();
for(int i = 0 ; i < Guides.size() ; i ++ ) {
for (int b = 0; b < Guides.get(i).English.size() ; b++){
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishHTC());
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishNexus());
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishSamsung());
Log.LogInfo("English Result Is: " + Guides.get(i).English.get(i).getEnglishSony());
}
for (int b = 0; b < Guides.get(i).Arabic.size() ; b++){
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicHTC());
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicNexus());
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicSamsung());
Log.LogInfo("Arabic Result Is: " + Guides.get(i).Arabic.get(i).getArabicSony());
}
}
My work isn't correct, and getting a lot of errors,
Here's the last error i got :
`Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 3 column 18 path $.Guides
What's the way to make it correct ? `
Based on your models when you try to get the guides list your telling retrofit to populate an array. Retrofit is then getting the data and finding that it is a single object and not array. So you need to update your model to reflect the data returned. For example:
class PostItem {
List<Language> mLanguages;
}
class Language{
String mLanguageTitle; //for example english
List<String> mData; //for this is your list of data
}
Then in your activity instead of getting guides you would get just a post item for example:
response.body().getPostItem();
Hope it helps !
First of all, you can use the retrofit Gson library.
You can handle this in two ways:
Option 1: reformat your languages in your json to be an array like Doug says.
{
"Guides":
[
{"Lang":"English","ArabicSony":"Test1","ArabicNexus":"Test2","ArabicSamsung":"Test3","ArabicHTC":"Test4"}
, {"Lang":"Arabic","EnglishSony":"Test1","EnglishNexus":"Test2","EnglishSamsung":"Test3","EnglishHTC":"Test4"}
]
}
Then you will need to redesign your class to reflect this structure.
Like Doug sayd:
class PostItem {
List<Language> mLanguages;
}
Option 2: Create a custom json desirializer in your class. this will take the Json and break it down into whatever structure you want it to be.
public class PostItem implements JsonDeserializer
#Override
public MyDesirializer deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonObject jarabic = (JsonObject) json.get("Arabic");
//whatever manipulations you want to do (fill with your own code)
PostItem item = new PostItem();
item.arabic = jarabic;
...
...
return item;
}
I can't seem to figure out how to get android annotations rest client to work I'm having 2 main issues.
A)How to parse the generic json response and get the meaningful key
B)How to add parameters
For the first problem all responses come back as a json string fomatted like this
{"success":,"message":"","data":{}}
Where success is boolean message is a string and data is going to be the main data I want to parse that may be a boolean, an array, a string or an int
I'm pretty sure I need to intercept the response and handle the code but I'm not sure how to do that
Lets use a real response that look something like this
{"success":true,"message":"random message","data":{"profile":{"id":"44","user_id":"44","name":"Matt","username":"mitch","icon":"b1da7ae15027b7d6421c158d644f3220.png","med":"2a3df53fb39d1d8b5edbd0b93688fe4a.png","map":"b7bfed1f456ca4bc8ca748ba34ceeb47.png","background":null,"mobile_background":null}}
First in my interceptor I want to see if the boolean key "success" is true and then return the data value
#EBean
public class RestInterceptor implements ClientHttpRequestInterceptor {
final String TAG = "rest";
#Bean
AuthStore authStore;
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] data, ClientHttpRequestExecution execution)
throws IOException{
//Need to set the api key here but nothing happens code quits
// Log.d("Rest",authStore.getApiKey());
HttpHeaders headers = request.getHeaders();
headers.set("api_key","");
ClientHttpResponse resp = execution.execute(request, data);
HttpStatus code = resp.getStatusCode();
if(code.value() == 200){
Log.d(TAG,"success code 200");
//valid http request but is it a valid API request?
//perform some logic of if success == true in root json object
//if true cast return data key
}
else{
Log.d(TAG,"fail code" + code.toString());
}
return resp;
}
}
The second problem is sending params with the http request that have an api key and a session key, I define the application class like this
#EApplication
public class MyApp extends Application {
final String TAG = "app";
#Bean
AuthStore authStore;
#RestService
RestClient restClient;
public void onCreate() {
super.onCreate();
init();
}
#AfterInject
public void init() {
authStore.setApiKey("dummy_key");
Log.d(TAG, "api key set to " + authStore.getApiKey());
}
}
With the AuthStore class like this
#EBean(scope = Scope.Singleton)
public class AuthStore {
public String apiKey,sessionKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sessionKey) {
this.sessionKey = sessionKey;
}
}
Basically I'm setting a dummy api key at the application level in a singleton, which I should be able to access in the rest interceptor interface but the code just quits without errors I'm basically following this guide https://github.com/excilys/androidannotations/wiki/Authenticated-Rest-Client
Finally I have an activity class which injects the app dependency which has refrence to the rest http class and the authstore class
#EActivity(R.layout.activity_login)
public class LoginActivity extends Activity {
#App
MyApp app;
#ViewById
TextView email;
#ViewById
TextView password;
#ViewById
Button loginButton;
#AfterInject
public void init() {
Log.d(app.TAG, "api in login key set to " + app.authStore.getApiKey());
}
#Click
#Trace
void loginButton() {
login(email.toString(), password.toString());
}
#Background
void login(String email, String password) {
app.restClient.forceLogin();
}
}
Sorry if it's a lot of info, I've been searching for a while and can't figure this out!
thanks in advance
I'm not known with the library you're using (annotations, spring) but it seems to me that you are struggling with parsing the success = true because that is not supposed to be in the JSON.
The JSON should preferably represent a class in your app 1on1 so you can easily map that into an object.
Communication between your app and the webservice, regarding the status of requests should go into the headers.
Like this you can check a request's headers, before parsing the JSON.
This is mathod I am using to parse any JSON object recursively.
private void parseJson(JSONObject data) {
if (data != null) {
Iterator<String> it = data.keys();
while (it.hasNext()) {
String key = it.next();
try {
if (data.get(key) instanceof JSONArray) {
JSONArray arry = data.getJSONArray(key);
int size = arry.length();
for (int i = 0; i < size; i++) {
parseJson(arry.getJSONObject(i));
}
} else if (data.get(key) instanceof JSONObject) {
parseJson(data.getJSONObject(key));
} else {
System.out.println("" + key + " : " + data.optString(key));
}
} catch (Throwable e) {
System.out.println("" + key + " : " + data.optString(key));
e.printStackTrace();
}
}
}
}
I'm trying this code, but not working
public class Main {
public static void main(String[] args) { list();}
private static void list() {
Gson gson = new Gson();
String result = "[{\"Person\":{\"id\":\"1\",\"name\":\"Prédio I\"}},{\"Person\":{\"id\":\"2\",\"name\":\"Prédio II\"}}]";
Person[] persons = gson.fromJson(result, Person[].class);
System.out.println("Qtde: " + persons.length);
for (Person pe : persons) {
System.out.println("Name: " + pe.getName());
}
}
}
see that this code takes an array of Persons, but not works, should show me javabens objects
I'm guessing that the problem is with properly binding the JSON structure to a matching Java data structure. Note that each component in the JSON array is an object that has a single property, named "Person", which is an object with two properties, named "id" and "name" -- each component in the JSON array is not a simple Person object, but a Person wrapper object.
The following demonstrates binding the JSON to a matching Java data structure.
import com.google.gson.Gson;
public class GsonFoo
{
public static void main(String[] args)
{
// [{"Person":{"id":"1","name":"Prédio I"}},{"Person":{"id":"2","name":"Prédio II"}}]
String jsonInput = "[{\"Person\":{\"id\":\"1\",\"name\":\"Prédio I\"}},{\"Person\":{\"id\":\"2\",\"name\":\"Prédio II\"}}]";
PersonWrapper[] persons = new Gson().fromJson(jsonInput, PersonWrapper[].class);
System.out.println("Qtde: " + persons.length);
for (PersonWrapper pw : persons)
{
System.out.println("Name: " + pw.Person.name);
}
// output:
// Qtde: 2
// Name: Prédio I
// Name: Prédio II
}
}
class PersonWrapper
{
Person Person;
}
class Person
{
int id;
String name;
}