Retrofit with UrlEncoded Object - android

I could not find the correct information on this subject. The problem has already been mentioned, but there is no correct solution. No problem with request like:
#FormUrlEncoded
#POST("/guide/confirm")
Call<Model> confirm(#Field("step") String step, #Field("code") String code);
But, what is correct (!) way do encode all object, which has three or more list of other object. Parent and child object fields most converted with UrlEncoded.
// What need to do, to encode all data below?
#POST("/guide/loadinfo")
Call<Model> confirm(#Body VeryBigJsonObject object);
There was solution using TypedObject - but now is functions is deprecated, and it is not a new retrofit. I hope you can help.
JakeWharton says in some issues, that my json is not url enoded form (its too large). That is mean, that I cannot send my request to server using Retrofit? Some example json: http://www.jsoneditoronline.org/?id=661b2bae9eb520902825a58f8d44c338

I have so much troubles with sending whole class with form-urlencoded, because our server does not allow json.
I don't think it's correct way, but i dont find any better solution.
(i tried send my class by fields, but retrofit can't encode arrays in fields correctly)
After spending a lot of time, i did it like this:
public static RequestBody objectToRequestBody(Object obj)
{
String jsonString = new Gson().toJson(obj);
String reqestText = "";
try {
Object jsonObj = new JSONObject(jsonString);
reqestText = Tools.jsonToURLEncodingAux(jsonObj,"",0);
} catch (JSONException e) {
e.printStackTrace();
}
String mediaType = "application/x-www-form-urlencoded";
return RequestBody.create(okhttp3.MediaType.parse(mediaType), reqestText);
}
public static String jsonToURLEncodingAux(Object json, String prefix, int level) {
String output = "";
if (json instanceof JSONObject) {
JSONObject obj = (JSONObject)json;
Iterator<String> keys1 = obj.keys();
while (keys1.hasNext())
{
String currKey = keys1.next();
String subPrefix = "";
if(level>0) {
subPrefix = prefix + "[" + currKey + "]";
} else {
subPrefix = prefix + currKey;
}
try {
output += jsonToURLEncodingAux(obj.get(currKey), subPrefix, level + 1);
} catch (JSONException e) {
e.printStackTrace();
}
}
} else if (json instanceof JSONArray) {
JSONArray jsonArr = (JSONArray) json;
int arrLen = jsonArr.length();
for (int i = 0; i < arrLen; i++) {
String subPrefix = prefix + "[" + i + "]";
Object child = null;
try {
child = jsonArr.get(i);
output += jsonToURLEncodingAux(child, subPrefix, level + 1);
} catch (JSONException e) {
e.printStackTrace();
}
}
} else {
output = prefix + "=" + json.toString() + "&";
}
return output;
}
interface:
#Headers("Cache-Control: max-age=259200")
#POST("api/route/report/")
Observable<ReportResponsePOJO> sendReport(
#Header("Content-Type") String content_type,
#Body RequestBody report
);
and send it like this
Observable<ReportResponsePOJO> myResponsePOJOObservable = apiInterface
.sendReport(
"application/x-www-form-urlencoded",
objectToRequestBody(report))
.subscribeOn(Schedulers.io());
I hope it will work, at least for me.

Related

How to get Retrofit 2 error from array body

My current response is
{"response":"validation error","status":"failure","code":400,"errors":["You can not add multiple items with different categories"]}
My current code is :
String errorBody = response.errorBody().string();
JSONObject jsonObject = new JSONObject(errorBody.trim());
jsonObject = jsonObject.getJSONObject("errors");
Iterator<String> keys = jsonObject.keys();
String errors = "";
while (keys.hasNext()) {
String key = keys.next();
JSONArray arr = jsonObject.getJSONArray(key);
for (int i = 0; i < arr.length(); i++) {
errors += key + " : " + arr.getString(i) + "\n";
}
}
I am trying to get the error code to see if it matches specific keywords to handle the response
i think your current code its not to good,better way for u is:
create modelClass for your json output and in retrofit calls write:
if (model.status=='failure' || model.code==400){
print(response.message) // or something like this
}
You can look through the following code snippet
call.enqueue(new Callback<PagedResponse<NotificationModel>>() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onResponse(Call<PagedResponse<NotificationModel>> call, Response<PagedResponse<NotificationModel>> response) {
if (response.isSuccessful()) {
if (response.code() == 200) {
try {
PagedResponse<NotificationModel> notifications = (PagedResponse<NotificationModel>) response.body();
tvRecordsCount.setText("Total "+response.body().getTotal()+" Notifications ");
showNotification(notifications);
} catch (Exception e){
e.printStackTrace();
}
} else {
showToast(getApplicationContext(), "Server Error");
}
}
}
#Override
public void onFailure(Call<PagedResponse<NotificationModel>> call, Throwable t) {
showToast(getApplicationContext(), t.getMessage());
}
});
I managed to get it working with this code:
String errors = "";
String errorBody = response.errorBody().string();
JsonParser parser = new JsonParser();
JsonObject rootObj = parser.parse(errorBody.trim()).getAsJsonObject();
JsonArray errorArray = rootObj.getAsJsonArray("errors");
for (JsonElement pa : errorArray) {
errors = pa.getAsString();
}

How do I iterate over a JSONObject to find the last data point?

I need to get the last element in a JSONObject, to retrieve the object my code is:
val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
Response.Listener { response ->
Log.i("response", "Response: %s".format(response.toString()))
var jsona: JSONObject = response.getJSONObject("daily")
},
Response.ErrorListener { error ->
Log.i("error", "Error: %s".format(error.toString()))
}
)
And so I acquire the daily value with the jsona variable
{"1582934400000":12450,"1583020800000":12639,"1583107200000":12439,"1583193600000":12348,"1583280000000":12278,"1583366400000":12322,"1583452800000":12435}
Is there an intelligent way to parse this data to find the value ("1583452800000":12435) or more preferably the 12435?
It seems like I can only access data within the object by knowing the string, but the string should change and I only ever need that last data point.
Getting the element with the biggest key (also last data point):
var top: Long = 0
for (key in jsona.keys()){
if (key.toLong() > top) {
top = key.toLong()
}
}
Then accessing it with
jsona.get(top.toString())
Just was hoping for a more efficient solution.
I have tested successfully with below codes:
int result = 0;
String json = "{ \"1582934400000\": 12450, \"1583020800000\": 12639, \"1583452800000\": 12435}";
try {
JSONObject convertedObject = new JSONObject(json);
Iterator<?> keys = convertedObject.keys();
while (keys.hasNext()) {
result = convertedObject.getInt((String) keys.next()); //result is 12435
}
} catch (JSONException e) {
e.printStackTrace();
}
You could refer it.
try {
String json = "{ \"1582934400000\": 12450, \"1583020800000\": 12639, \"1583452800000\": 12435}";
JSONObject obj = new JSONObject(json);
Iterator<String> keyItr = obj.keys();
String lastValue="";
while(keyItr.hasNext()) {
String key = keyItr.next();
lastValue = obj.getString(key);
}
Log.d("last val=",lastValue);
} catch (JSONException e) {
e.printStackTrace();
}
Can be the other way.

Android parse JSONObject

I've got a little problem with parsing json into my android app.
This is how my json file looks like:
{
"internalName": "jerry91",
"dataVersion": 0,
"name": "Domin91",
"profileIconId": 578,
"revisionId": 0,
}
As You can see this structure is a little bit weird. I dont know how to read that data in my app. As I noticed those are all Objects not arrays :/
You can always use good old json.org lib. In your Java code :
First read your json file content into String;
Then parse it into JSONObject:
JSONObject myJson = new JSONObject(myJsonString);
// use myJson as needed, for example
String name = myJson.optString("name");
int profileIconId = myJson.optInt("profileIconId");
// etc
UPDATE 2018
After 5 years there is a new "standard" for parsing json on android. It's called moshi and one can consider it GSON 2.0. It's very similar but with design bugs fixed that are the first obstacles when you start using it.
https://github.com/square/moshi
First add it as a mvn dependency like this:
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi-kotlin</artifactId>
<version>1.6.0</version>
</dependency>
After adding it we can use like so (taken from the examples):
String json = ...;
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<BlackjackHand> jsonAdapter = moshi.adapter(BlackjackHand.class);
BlackjackHand blackjackHand = jsonAdapter.fromJson(json);
System.out.println(blackjackHand);
More infos on their GitHub page :)
[old]
I would recommend using Gson.
Here are some links for tutorials:
how to convert java objecto from json format using GSON
Parse JSON file using GSON
Simple GSON example
Converting JSON data to Java object
An alternative to Gson you could use Jackson.
Jackson in 5 minutes
how to convert java object to and from json
This libraries basically parse your JSON to a Java class you specified.
to know if string is JSONArray or JSONObject
JSONArray String is like this
[{
"internalName": "blaaa",
"dataVersion": 0,
"name": "Domin91",
"profileIconId": 578,
"revisionId": 0,
},
{
"internalName": "blooo",
"dataVersion": 0,
"name": "Domin91",
"profileIconId": 578,
"revisionId": 0,
}]
and this String as a JSONOject
{
"internalName": "domin91",
"dataVersion": 0,
"name": "Domin91",
"profileIconId": 578,
"revisionId": 0,
}
but how to call elements from JSONArray and JSONObject ?
JSNOObject info called like this
first fill object with data
JSONObject object = new JSONObject(
"{
\"internalName\": \"domin91\",
\"dataVersion\": 0,
\"name\": \"Domin91\",
\"profileIconId\": 578,
\"revisionId\": 0,
}"
);
now lets call information from object
String myusername = object.getString("internalName");
int dataVersion = object.getInt("dataVersion");
If you want to call information from JSONArray you must know what is the object position number or you have to loop JSONArray to get the information for example
looping array
for ( int i = 0; i < jsonarray.length() ; i++)
{
//this object inside array you can do whatever you want
JSONObject object = jsonarray.getJSONObject(i);
}
if i know the object position inside JSONArray ill call it like this
//0 mean first object inside array
JSONObject object = jsonarray.getJSONObject(0);
This part do in onBackground in AsyncTask
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl(url);
try {
result = json.getString("internalName");
data=json.getString("dataVersion");
ect..
} catch (JSONException e) {
e.printStackTrace();
}
JsonParser
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
// constructor
public JSONParser() {
}
public JSONObject getJSONFromUrl(String url) {
// Making HTTP request
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "utf-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
}
I suggest you to use a library like gson as #jmeier wrote on his answer. But if you want to handle json with android's defaults, you can use something like this:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String s = new String("{\"internalName\": \"domin91\",\"dataVersion\": 0,\"name\": \"Domin91\",\"profileIconId\": 578,\"revisionId\": 0,}");
try {
MyObject myObject = new MyObject(s);
Log.d("MY_LOG", myObject.toString());
} catch (JSONException e) {
Log.d("MY_LOG", "ERROR:" + e.getMessage());
}
}
private static class MyObject {
private String internalName;
private int dataVersion;
private String name;
private int profileIconId;
private int revisionId;
public MyObject(String jsonAsString) throws JSONException {
this(new JSONObject(jsonAsString));
}
public MyObject(JSONObject jsonObject) throws JSONException {
this.internalName = (String) jsonObject.get("internalName");
this.dataVersion = (Integer) jsonObject.get("dataVersion");
this.name = (String) jsonObject.get("name");
this.profileIconId = (Integer) jsonObject.get("profileIconId");
this.revisionId = (Integer) jsonObject.get("revisionId");
}
#Override
public String toString() {
return "internalName=" + internalName +
"dataVersion=" + dataVersion +
"name=" + name +
"profileIconId=" + profileIconId +
"revisionId=" + revisionId;
}
}
}
Please checkout ig-json parser or Logan Square for fast and light JSON library.
For comparison, this is the stats from Logan Square developer.
Here you can parse any file from assets folder
fetch file from assets folder
public void loadFromAssets(){
try {
InputStream is = getAssets().open("yourfile.json");
readJsonStream(is);
} catch (IOException e) {
e.printStackTrace();
}
}
Convert JSON to your class object
public void readJsonStream(InputStream in) throws IOException {
Gson gson = new Gson();
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
reader.setLenient(true);
int size = in.available();
Log.i("size", size + "");
reader.beginObject();
long starttime=System.currentTimeMillis();
while (reader.hasNext()) {
try {
Yourclass message = gson.fromJson(reader, Yourclass.class);
}
catch (Exception e){
Toast.makeText(this, e.getCause().toString(), Toast.LENGTH_SHORT).show();
}
}
reader.endObject();
long endtime=System.currentTimeMillis();
long diff=endtime-starttime;
int seconds= (int) (diff/1000);
Log.i("elapsed",seconds+"");
reader.close();
}

JSON Parsing, structure assistance

JsonFactory f = new MappingJsonFactory();
JsonParser jp = f.createParser(res);
JsonToken current;
current = jp.nextToken();
if (current != JsonToken.START_OBJECT) {
System.out.println("Error: root should be object: quiting.");
return;
}
while (jp.nextToken() != JsonToken.END_OBJECT) {
String fieldName = jp.getCurrentName();
// move from field name to field value
current = jp.nextToken();
if (fieldName.equals("row")) {
if (current == JsonToken.START_ARRAY) {
while (jp.nextToken() != JsonToken.END_ARRAY) {
JsonNode node = jp.readValueAsTree();
Log.e("KFF", node.get("col0").asText());
}
} else {
Log.e("KFF", "Error: records should be an array: skipping.");
jp.skipChildren();
}
} else {
Log.e("KFF", "Unprocessed property: " + fieldName);
jp.skipChildren();
}
}
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20csv%20where%20url%3D%22http%3A%2F%2Fichart.finance.yahoo.com%2Ftable.csv%3Fs%3DYHOO%26a%3D11%26b%3D10%26c%3D2011%26d%3D10%26e%3D10%26f%3D2013%26g%3Dd%22%3B&format=json&diagnostics=true&callback=
I'm currently using the above to parse JSON responses from the web (USING THE JACKSON JSON PARSING LIBARY) , however i'm at a loss at to how to parse nested json arrays such as the following, i.e. how to go down into each json array until 'row' and then be able to read each 'colx' eliminating 'unprocessed property'
Sorry about the horrendous quality of English in that, it's late and i'm at a loss in terms of describing it.
Something like this should work for you. Disclaimer - totally untested. This will put you in the right direction though.
// Assuming the json is in a String called jsonString
JSONObject jsonObj = new JSONObject(jsonString);
JSONArray jsonArray = jsonObj.getJSONObject("query").getJSONObject("results").getJSONArray("row");
int arrayCount = jsonArray.length();
for(int i=0; i < arrayCount; i++){
JSONObject jsonData = jsonArray.getJSONObject(i);
String col0 = jsonData.getString("col0");
String col1 = jsonData.getString("col1");
// etc, etc ...
// put those values in arrays or whatever here.
}

conversion from string to JSON object Android

I am working on an Android application. In my app I have to convert a string to JSON Object, then parse the values. I checked for a solution in Stackoverflow and found similar issue here link
The solution is like this
`{"phonetype":"N95","cat":"WP"}`
JSONObject jsonObj = new JSONObject("{\"phonetype\":\"N95\",\"cat\":\"WP\"}");
I use the same way in my code . My string is
{"ApiInfo":{"description":"userDetails","status":"success"},"userDetails":{"Name":"somename","userName":"value"},"pendingPushDetails":[]}
string mystring= mystring.replace("\"", "\\\"");
And after replace I got the result as this
{\"ApiInfo\":{\"description\":\"userDetails\",\"status\":\"success\"},\"userDetails\":{\"Name\":\"Sarath Babu\",\"userName\":\"sarath.babu.sarath babu\",\"Token\":\"ZIhvXsZlKCNL6Xj9OPIOOz3FlGta9g\",\"userId\":\"118\"},\"pendingPushDetails\":[]}
when I execute JSONObject jsonObj = new JSONObject(mybizData);
I am getting the below JSON exception
org.json.JSONException: Expected literal value at character 1 of
Please help me to solve my issue.
Remove the slashes:
String json = {"phonetype":"N95","cat":"WP"};
try {
JSONObject obj = new JSONObject(json);
Log.d("My App", obj.toString());
} catch (Throwable t) {
Log.e("My App", "Could not parse malformed JSON: \"" + json + "\"");
}
This method works
String json = "{\"phonetype\":\"N95\",\"cat\":\"WP\"}";
try {
JSONObject obj = new JSONObject(json);
Log.d("My App", obj.toString());
Log.d("phonetype value ", obj.getString("phonetype"));
} catch (Throwable tx) {
Log.e("My App", "Could not parse malformed JSON: \"" + json + "\"");
}
try this:
String json = "{'phonetype':'N95','cat':'WP'}";
You just need the lines of code as below:
try {
String myjsonString = "{\"phonetype\":\"N95\",\"cat\":\"WP\"}";
JSONObject jsonObject = new JSONObject(myjsonString );
//displaying the JSONObject as a String
Log.d("JSONObject = ", jsonObject.toString());
//getting specific key values
Log.d("phonetype = ", jsonObject.getString("phonetype"));
Log.d("cat = ", jsonObject.getString("cat");
}catch (Exception ex) {
StringWriter stringWriter = new StringWriter();
ex.printStackTrace(new PrintWriter(stringWriter));
Log.e("exception ::: ", stringwriter.toString());
}
just try this ,
finally this works for me :
//delete backslashes ( \ ) :
data = data.replaceAll("[\\\\]{1}[\"]{1}","\"");
//delete first and last double quotation ( " ) :
data = data.substring(data.indexOf("{"),data.lastIndexOf("}")+1);
JSONObject json = new JSONObject(data);
To get a JSONObject or JSONArray from a String I've created this class:
public static class JSON {
public Object obj = null;
public boolean isJsonArray = false;
JSON(Object obj, boolean isJsonArray){
this.obj = obj;
this.isJsonArray = isJsonArray;
}
}
Here to get the JSON:
public static JSON fromStringToJSON(String jsonString){
boolean isJsonArray = false;
Object obj = null;
try {
JSONArray jsonArray = new JSONArray(jsonString);
Log.d("JSON", jsonArray.toString());
obj = jsonArray;
isJsonArray = true;
}
catch (Throwable t) {
Log.e("JSON", "Malformed JSON: \"" + jsonString + "\"");
}
if (object == null) {
try {
JSONObject jsonObject = new JSONObject(jsonString);
Log.d("JSON", jsonObject.toString());
obj = jsonObject;
isJsonArray = false;
} catch (Throwable t) {
Log.e("JSON", "Malformed JSON: \"" + jsonString + "\"");
}
}
return new JSON(obj, isJsonArray);
}
Example:
JSON json = fromStringToJSON("{\"message\":\"ciao\"}");
if (json.obj != null) {
// If the String is a JSON array
if (json.isJsonArray) {
JSONArray jsonArray = (JSONArray) json.obj;
}
// If it's a JSON object
else {
JSONObject jsonObject = (JSONObject) json.obj;
}
}
Using Kotlin
val data = "{\"ApiInfo\":{\"description\":\"userDetails\",\"status\":\"success\"},\"userDetails\":{\"Name\":\"somename\",\"userName\":\"value\"},\"pendingPushDetails\":[]}\n"
try {
val jsonObject = JSONObject(data)
val infoObj = jsonObject.getJSONObject("ApiInfo")
} catch (e: Exception) {
}
Here is the code, and you can decide which
(synchronized)StringBuffer or
faster StringBuilder to use.
Benchmark shows StringBuilder is Faster.
public class Main {
int times = 777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = times; i --> 0 ;) {
sb.append("");
getJSONFromStringBuffer(String stringJSON);
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = times; i --> 0 ;) {
getJSONFromStringBUilder(String stringJSON);
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
private String getJSONFromStringBUilder(String stringJSONArray) throws JSONException {
return new StringBuffer(
new JSONArray(stringJSONArray).getJSONObject(0).getString("phonetype"))
.append(" ")
.append(
new JSONArray(employeeID).getJSONObject(0).getString("cat"))
.toString();
}
private String getJSONFromStringBuffer(String stringJSONArray) throws JSONException {
return new StringBuffer(
new JSONArray(stringJSONArray).getJSONObject(0).getString("phonetype"))
.append(" ")
.append(
new JSONArray(employeeID).getJSONObject(0).getString("cat"))
.toString();
}
}
May be below is better.
JSONObject jsonObject=null;
try {
jsonObject=new JSONObject();
jsonObject.put("phonetype","N95");
jsonObject.put("cat","wp");
String jsonStr=jsonObject.toString();
} catch (JSONException e) {
e.printStackTrace();
}

Categories

Resources