I am trying to parse JSON response in android. But not able to handle dynamic JSON format.
Here is a JSON response:
{
"code":"1",
"data":{
"220":{
"reg_no":"12",
"device_status":"off"
},
"218":{
"reg_no":"11",
"device_status":"on"
}
}
}
220 and 219 are dynamic values.
Calling API from MainActivity.java
public void getItemData() {
Call<ItemData> call = service.getItemData(token,vehicle_ids);
call.enqueue(new Callback<ItemData>() {
#Override
public void onResponse(#NonNull Call<ItemData> call,#NonNull Response<ItemData> response) {
Log.d("Response",response.body.toString());
progressDoalog.dismiss();
}
#Override
public void onFailure(#NonNull Call<ItemData> call,#NonNull Throwable t) {
progressDoalog.dismiss();
}
});
}
Create ItemData Class to handle response:
ItemData.java
public class ItemData {
private String code;
private VehicleData data = new VehicleData();
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public VehicleData getData() {
return data;
}
public void setData(VehicleData data) {
this.data = data;
}
}
VehicleData.java
public class VehicleData{
}
I am getting response:
code: 1
data : null
Please suggest me How should I change my VehicleData.java class so that I can handle
response.
The same thing can also be done using GSON, but instead of using GSON converter adapter to convert into to POJO. we will parse it manually. which gives us flexibility in case of dynamic JSON data.
let's say the JSON format is like below in my case.
{
"code":"1",
"data":{
"220":{
"reg_no":"12",
"device_status":"off"
},
"218":{
"reg_no":"11",
"device_status":"on"
}
}
}
in this case the dateWiseContent has dynamic object keys so we will parse this json string using JsonParser class.
//parsing string response to json object
JsonObject jsonObject = (JsonObject) new JsonParser().parse(resource);
//getting root object
JsonObject data = jsonObject.get("data").getAsJsonObject();
get the dynamic keys using Map.Entry as given below
// your code goes here
for (Map.Entry<String, JsonElement> entry : data.entrySet()) {
//this gets the dynamic keys
String dateKey = entry.getKey();
//you can get any thing now json element,array,object according to json.
JsonArray jsonArrayDates = entry.getValue().getAsJsonArray();
int appointmentsSize = jsonArrayDates.size();
for (int count = 0; count < appointmentsSize; count++) {
JsonObject objectData = jsonArrayDates.get(count).getAsJsonObject();
String device_status = objectData.get("device_status").getAsString();
}
}
similarly any level of dynamic json can be parsed using Map.Entry
I solved this using Hashmap.
public class ItemData {
Hashmap<String, object> data = new hashmap<>();
}
and using getter setter I can access variables.
Related
I am confused as to what a JSON Object is and what a JSON String is. Which part is a JSON Object, and which is a JSON String?
JSON example 1:
{
"abc":"v1",
"def":"v2"
}
JSON example 2:
{
"res":"false",
"error":{
"code":101
}
}
Given by your first example:
try {
JSONObject obj = new JSONObject(json);
String abc = obj.get("abc");
String def = obj.get("def");
} catch (Throwable t) {
// Log something maybe?
}
Simply create a JSONObject with that string in the constructor.
JSONObject obj = new JSONObject(your_string_goes_here);
Your JSON string is the entire visual representation that you see (encoded as a string):
{
"abc":"v1",
"def":"v2"
}
You can tell where a specific JSON Object starts and ends within your string, by looking for that opening brace { and the closing brace '}'.
In your examples, this is a JSON Object:
{
"abc":"v1",
"def":"v2"
}
So is this:
{
"res":"false",
"error": {
"code":101
}
}
And this:
{
"code":101
}
Use GSON for parsing & below are the model classes for json1 & json2
public class Json1 {
/**
* abc : v1
* def : v2
*/
private String abc;
private String def;
public String getAbc() {
return abc;
}
public void setAbc(String abc) {
this.abc = abc;
}
public String getDef() {
return def;
}
public void setDef(String def) {
this.def = def;
}
}
Json2
public class Json2 {
/**
* res : false
* error : {"code":101}
*/
private String res;
/**
* code : 101
*/
private ErrorBean error;
public String getRes() {
return res;
}
public void setRes(String res) {
this.res = res;
}
public ErrorBean getError() {
return error;
}
public void setError(ErrorBean error) {
this.error = error;
}
public static class ErrorBean {
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
}
I have used GsonFormatter plugin for creating model classes, Use Gson, It is super easy and you dont need to parse anything
JSON comprises JSONObject & JSONArray.
Json-1 is JSONObject while JSON -2 is also JSONObject which contains another JSONObject with a key "error".JSON String is the string representation of JSONObject which you can get by JSONObject jsonObject = new JSONObject(); String jsonString = jsonObject.toString();
Data is represented in name/value pairs.
"abc":"v1"
Curly braces hold objects and each name is followed by ':'(colon), the name/value pairs are separated by , (comma).
{
"abc":"v1",
"def":"v2"
}
Code Example:
JSONObject obj = new JSONObject(jsonStr);
String abc = obj.get("abc");
Square brackets hold arrays and values are separated by ,(comma).
{
"books": [
{
"id":"01",
"language": "Java",
"edition": "third",
"author": "Herbert Schildt",
},
{
"id":"07",
"language": "C++",
"edition": "second",
"author": "E.Balagurusamy",
}
]
}
Code Example:
JSONArray arrBooks = new JSONArray("books");
for (int i = 0; i<=arrBooks.length(); i++){
JSONObject objBook = arrBooks.getJSONObject(i);
String id = c.getString("id");
}
This my JSON response:
{
"id": 2,
"name": "Test",
"content": "{\"type\": \"status\", \"text\": \"Lorem ipsum dummy text.\", \"id\": 1}"
}
These are model structures:
class TestModel {
public int id;
public String name;
public Content content;
}
class Content {
public int id;
public String status;
public String text;
}
I want to parse content's value directly into my Content model object using Retrofit and GsonConvertor. But currently, I am parsing it as a String value than by using Gson.fromJson() convert to my Content model object. Is there any solution to get my expected result?
When I used to parse it using GsonConverterFactory, Retrofit gives callback in onFailure method with this exception:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 4 column 19 path $.data[0].content
The issue is with the JSON response, it is not in the correct JSON format. The "content" field should be an object, not a string:
{
"id": 2,
"name": "Test",
"content": {
"type": "status",
"text": "Lorem ipsum dummy text.",
"id": 1
}
}
This will allow either gson.fromJson(response, TestModel.class) or RetroFit with a GsonConverterFactory to parse your response correctly into the corresponding object.
Of course, this only applies if you have the ability to change the JSON response you are receiving. If not, first make sure the person who is in control of the response knows that they are doing it wrong. If nothing changes, then you should be able to work around this by changing the content in TestModel to a String:
class TestModel {
public int id;
public String name;
public String content;
}
class Content {
public int id;
public String type;
public String text;
}
Then parsing each object separately:
TestModel testModel = gson.fromJson(response, TestModel.class);
Content content = gson.fromJson(testModel.content, Content.class);
If the response cannot be changed, another option is to create a TypeAdapter for your Content object:
public class ContentAdapter extends TypeAdapter<Content> {
#Override
public void write(JsonWriter out, Content value) throws IOException {
// TODO: Writer implementation
}
#Override
public Content read(JsonReader in) throws IOException {
if(in.peek() != JsonToken.NULL) {
return fromJson(in.nextString());
} else {
in.nextNull();
return null;
}
}
}
Then add the TypeAdapter to your GSON implementation:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Content.class, new ContentAdapter()).create();
Hope you are using retrofit version 2.1.0, in this version you can choose the parsers of your choice, but in the previous version Gson was inbuilt parser. I assume you need to use Gson. for that you have to set converterFactory as GsonConverterFactory, example is given below.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
This will add Gson as your json parser.
Check out this tutorial. also read the documentation here.
Dont forget to add this in your gradle
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Parser {
public static List<TestModel> JsonParser(String JsonString) {
try {
JSONArray array = new JSONArray(content);
List<TestModel > arrayList = new ArrayList();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
TestModel model = new TestModel();
model.setId(Integer.parseInt(obj.getString("id")));
model.setName(obj.getString("name"));
JSONArray contentArray = newJSONArray(obj.getString("content")));
JSONObject obj1 = contentArray.getJSONObject(1);
Content content = new Content();
content.setId(Integer.parseInt(obj1.getString("id")));
content.setStatus(obj1.getString("status"));
content.setText(obj1.getString("text"));
model.setContent(content);
arrayList.add(model);
}
return arrayList;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
}
class TestModel {
//Generate Setter Getter for all properties
public int id;
public String name;
public Content content;
}
class Content {
//Generate Setter Getter for all properties
public int id;
public String status;
public String text;
}
I have a JSoN data like this:
{
"data": {
"noofCity": "1",
"City 1": [
{
"id": "12",
"title": "Delhi"
}
]
},
"success": true
}
Now based on noofCity next tag City 1 will be generated. If noofCity will be 2 then there are two tag City 1 and City 2. Then how can I parse it using Json? Please tell me how can I generate my POJO class structure.
Your POJOs should look like below:
Main POJO for Response:
public class Response {
Data data;
boolean success;
}
For Data
public class Data {
int noofCity;
Map<String, List<City>> cityMap;
void put(String key, List<City> city){
if(cityMap == null){
cityMap = new HashMap<>();
}
cityMap.put(key, city);
}
public void setNoofCity(int noofCity) {
this.noofCity = noofCity;
}
public int getNoofCity() {
return noofCity;
}
}
For City
public class City {
int id;
String title;
}
But one of the most important think is a way how to deserialise Data. You have to prepare your own deserialiser for this, and define way how to fill HashMap as is shown in the code below:
public class DataDeserializer implements JsonDeserializer<Data> {
#Override
public Data deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Data result = new Data();
Gson gson = new Gson();
JsonObject jsonObject= json.getAsJsonObject();
result.setNoofCity(jsonObject.get("noofCity").getAsInt());
for(int i =1; i<=result.getNoofCity() ; i++ ){
List<City> cities= gson.fromJson(jsonObject.getAsJsonArray("City "+ i), List.class);
result.put("City "+ i, cities);
}
return result;
}
}
And now you can deserialise you json
Gson gson = new GsonBuilder()
.registerTypeAdapter(Data.class, new DataDeserializer())
.create();
Response test = gson.fromJson(json, Response.class);
I don't know of the title is very accurate, but let me explain what I want.
I am having this long JSONObject (sadly it's not an array and I can't loop through it) with many other JSONObjects inside of it with similar elements (id, name, icon), and when I read through an element it writes its value in a separate class with implemented Parcelable.
Here is what my Parcelable class look like before I explain further:
public class ItemsInfo implements Parcelable {
public int itemId;
public String itemName, itemIcon;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(itemName);
dest.writeString(itemIcon);
dest.writeInt(itemId);
}
public static final Parcelable.Creator<ItemsInfo > CREATOR = new Parcelable.Creator<ItemsInfo >() {
#Override
public ItemsInfo createFromParcel(Parcel source) {
ItemsInfo ei = new ItemsInfo();
ei.itemName = source.readString();
ei.itemIcon = source.readString();
ei.itemId = source.readInt();
return ei;
}
#Override
public ItemsInfo [] newArray(int size) {
return new ItemsInfo [size];
}
};
}
what I want is everytime it reads through a JSONObject with the similar elements, to write them with an ArrayList in the String itemName, so later I can access a given item by only a index or something, and not to have to make separate strings and integers for every different item, like itemName1, itemName2, itemName3..... Is it possible?
You can use droidQuery to simplify JSON parsing. To convert your JSONObject to a Key-Value mapping, you can use this:
List<String> items = new ArrayList<String>();//this will contain your JSONObject strings
Map<String, ?> data = null;
try {
JSONObject json;//this references your JSONObject
data = $.map(json);
} catch (Throwable t) {
Log.e("JSON", "Malformed JSON Object");
}
Then, to loop through each element, just do this:
if (data != null) {
for (Map.Entry<String, ?> entry : data.entrySet()) {
items.add(entry.value().toString());
}
}
Now your List items is populated with the String representation of your JSONObejcts. Later, if you want to parse this JSON, just do:
int index = 2;//the index of the JSONObject you want
try {
Map<String, ?> data = $.map(new JSONObject(items.get(2)));
//now iterate the map
} catch (Throwable t) {
t.printStackTrace();//something wrong with your JSON string
}
I am developing an Android application and I access a RESTfull web service that returns a JSON. This JSON I want to put it in POJOs but I think I am missing something as it doesn't work.
The JSON retuned is as follow:
[{"CategoryName":"Food","Id":1},{"CategoryName":"Car","Id":2},{"CategoryName":"House","Id":3},{"CategoryName":"Work","Id":4}]
this is returned in response variable
String response = client.getResponse();
And now I try the following:
GsonBuilder gsonb = new GsonBuilder();
Gson gson = gsonb.create();
JSONObject j;
MainCategories cats = null;
try
{
j = new JSONObject(response);
cats = gson.fromJson(j.toString(), MainCategories.class);
}
catch(Exception e)
{
e.printStackTrace();
}
The error I get is:
09-02 07:06:47.009:
WARN/System.err(568):
org.json.JSONException: Value
[{"Id":1,"CategoryName":"Food"},{"Id":2,"CategoryName":"Car"},{"Id":3,"CategoryName":"House"},{"Id":4,"CategoryName":"Work"}]
of type org.json.JSONArray cannot be
converted to JSONObject
09-02 07:06:47.029:
WARN/System.err(568): at
org.json.JSON.typeMismatch(JSON.java:107)
Here are the POJO objects
MainCategories.java
public class MainCategories {
private List<CategoryInfo> category;
public List<CategoryInfo> getCategory() {
if (category == null) {
category = new ArrayList<CategoryInfo>();
}
return this.category;
}
}
CategoryInfo.java
public class CategoryInfo {
public String categoryName;
public Integer id;
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String value) {
this.categoryName = ((String) value);
}
public Integer getId() {
return id;
}
public void setId(Integer value) {
this.id = value;
}
}
To access the web service I use the class from: http://lukencode.com/2010/04/27/calling-web-services-in-android-using-httpclient/
Please help me as I am stuck for 2 days now and can't figure out how to continue. I found some subjects here but still didn't found a way around. Thank you very much.
Top level entity in your JSON string is JSONArray not JSONObject, while you're trying to parse it as object. Create an array from the string and use that.
JSONArray array = new JSONArray(response);