Deserialization unknow json with Gson - java

I got a free api for currency tracking with json:
api.coinmarketcap
I need deserialize this json to my compound java object with Gson library. This my model object:
public class Quote {
#SerializedName("quotes")
private String mName;
#SerializedName("price")
private double mPrice;
public Quote(String name, double price) {
mName = name;
mPrice = price;
}
public String getName() {
return mName;
}
public double getPrice() {
return mPrice;
}
}
and:
public class Currency {
private int mId;
private String mSymbol;
private byte mRank;
private String mWebsiteSlug;
private int mMaxSupply;
private Quote mQuote;
public Currency(int id, String symbol, byte rank, String websiteSlug, int maxSupply) {
mId = id;
mSymbol = symbol;
mRank = rank;
mWebsiteSlug = websiteSlug;
mMaxSupply = maxSupply;
}
public int getId() {
return mId;
}
public String getSymbol() {
return mSymbol;
}
public byte getRank() {
return mRank;
}
public String getWebsiteSlug() {
return mWebsiteSlug;
}
public int getMaxSupply() {
return mMaxSupply;
}
public Quote getQuote() {
return mQuote;
}
}
I can not deserialize with such nesting.

You can use enter link description here to create your pojo classes from json

I create currency deserializer:
public class CurrencyDeserializer implements JsonDeserializer<Currency> {
#Override
public Currency deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Currency currency = new Currency();
JsonObject currencyObject = json.getAsJsonObject();
JsonElement id = currencyObject.get("id");
if(!id.isJsonNull()) {
currency.setId(id.getAsInt());
}
JsonElement name = currencyObject.get("name");
if(!name.isJsonNull()) {
currency.setName(name.getAsString());
}
JsonElement symbol = currencyObject.get("symbol");
if(!symbol.isJsonNull()) {
currency.setSymbol(symbol.getAsString());
}
JsonElement slug = currencyObject.get("website_slug");
if(!slug.isJsonNull()) {
currency.setWebsiteSlug(slug.getAsString());
}
JsonElement rank = currencyObject.get("rank");
if(!rank.isJsonNull()) {
currency.setRank(rank.getAsLong());
}
JsonElement circulatingSupply = currencyObject.get("circulating_supply");
if(!circulatingSupply.isJsonNull()) {
currency.setCirculatingSupply(circulatingSupply.getAsLong());
}
JsonElement totalSupply = currencyObject.get("total_supply");
if(!totalSupply.isJsonNull()) {
currency.setTotalSupply(totalSupply.getAsLong());
}
JsonElement maxSupply = currencyObject.get("max_supply");
if(!maxSupply.isJsonNull()) {
currency.setMaxSupply(maxSupply.getAsLong());
}
JsonElement lastUpdated = currencyObject.get("last_updated");
if(!lastUpdated.isJsonNull()) {
Long l = lastUpdated.getAsLong() * 1000;
currency.setLastUpdated(new Date(l));
}
JsonObject quotes = currencyObject.get("quotes").getAsJsonObject();
for(Map.Entry<String, JsonElement> rootObj : quotes.entrySet())
{
Quote quote = context.deserialize(rootObj.getValue(), Quote.class);
quote.setName(rootObj.getKey());
currency.addQuote(quote);
}
return currency;
}
}
Simple and work

Related

JSON Parsing Android Java

i would like to parse this json but im not able to do it. Heres the Json Structure:
For example: I would like to get String product type => Car
this Code doesnt work:
JSONObject mainData = response.getJSONObject("decode");
String productType = mainData.getString("Product Type");
Please help
decode is an array not an object so it should be
JSONArray mainData = response.getJSONArray("decode");
And then you can get inside objects using the index.
JSONObject jsonObj = mainData.getJSONObject(0);
String answer = jsonObj.getString("label"); //Make
You can try to use Gson
Define your class with something like that
public class YourClass implements Parcelable {
private int price;
#SerializedName("price_currency")
private String priceCurrency;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getPriceCurrency() {
return priceCurrency;
}
public void setPriceCurrency(String priceCurrency) {
this.priceCurrency = priceCurrency;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(this.price);
dest.writeString(this.priceCurrency);
}
public YourClass() {
}
protected YourClass(Parcel in) {
super(in);
this.price = in.readInt();
this.priceCurrency = in.readString();
}
public static final Creator<YourClass> CREATOR = new Creator<YourClass>() {
#Override
public Pessoa createFromParcel(Parcel source) {
return new YourClass(source);
}
#Override
public YourClass[] newArray(int size) {
return new YourClass[size];
}
};
}
and try to convert your json with something like this
Gson gson = new Gson();
YourClass yourClass = gson.fromJson(yourJson, YourClass.class);
If you really want to do this correctly, you'll need a custom JsonDeserializer. Like this:
public class CarDeserializer implements JsonDeserializer<Car> {
#Override
public Car deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Car car = new Gson().fromJson(json.toString(), Car.class);
try {
JSONObject object = new JSONObject(json.toString());
car.setCurrency(Currency.getInstance(object.getString("price_currency")));
car.setBalance(object.getJSONObject("balance").getInt("API Decode"));
JSONArray decodeArray = object.getJSONArray("decode");
for (int i = 0; i < decodeArray.length(); i++){
JSONObject decodeObject = (JSONObject) decodeArray.get(i);
if (decodeObject.get("label").equals("Make")){
car.setMake(decodeObject.getString("value"));
} else if (decodeObject.get("label").equals("Manufacturer")){
car.setManufacturer(decodeObject.getString("value"));
} else if (decodeObject.get("label").equals("Plant Country")){
car.setPlantCountry(decodeObject.getString("value"));
} else if (decodeObject.get("label").equals("Product Type")){
car.setProductType(decodeObject.getString("value"));
}
}
} catch (JSONException e){
Log.e("CarDeserializer", e.toString(), e);
}
return car;
}
}
The Car object looks like this:
public class Car {
private int price;
private transient Currency currency;
private transient int balance;
private transient String make;
private transient String manufacturer;
private transient String plantCountry;
private transient String productType;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getPlantCountry() {
return plantCountry;
}
public void setPlantCountry(String plantCountry) {
this.plantCountry = plantCountry;
}
public String getProductType() {
return productType;
}
public void setProductType(String productType) {
this.productType = productType;
}
}
If Currency doesn't work for you, you can change that one to a String type like this:
#SerializedName("price_currency") private String currency;
And change the getter and setter accordingly.
If you have more objects in the decode array. You can add them as more branches in the deserializer.
This is used like this:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Car.class, new CarDeserializer());
Gson gson = gsonBuilder.create();
gson.fromJson(myJsonString, Car.class);
Note: The transient keyword in the Car class indicates to Gson that it shouldn't attempt to automatically parse the json for those fields.
Note 2: You'll need to include Gson in your project if you haven't already added it.

Android: parse JSON response when a key can be a JSON object or a JSON array

I am fetching data from API provided by our Backend team. One of the keys data sometimes contains JSONObject and sometimes it contains JSONArray. I am using GSON to parse the response and it is throwing an exception because of this.
I tried the solution given in this thread but it's not working in my case.
How to dynamically handle json response array/object using Gson
POJO (EntityDetailResponseV2):
package com.tf.eros.faythTv.objects.entityDetail;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.tf.eros.faythTv.objects.entityFeatured.EntityFeaturedResponse;
import com.tf.eros.faythTv.utils.ArrayAdapterFactory;
import java.util.List;
public class EntityDetailResponseV2 {
#SerializedName("results")
private Results results;
#SerializedName("success")
private boolean success;
public static EntityDetailResponseV2 getObject(String res) {
try {
Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create();
return gson.fromJson(res, EntityDetailResponseV2.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Results getResults() {
return results;
}
public boolean isSuccess() {
return success;
}
public static class Results {
#SerializedName("id")
Integer entityID;
#SerializedName("name")
String entityName;
#SerializedName("description")
String entityDescription;
#SerializedName("image_url")
String entityImageURL;
#SerializedName("square_entity_url")
String entitySquareURL;
#SerializedName("slug")
String entitySlug;
#SerializedName("live")
boolean isEntityLive;
#SerializedName("twitter_username")
String twitterUserName;
#SerializedName("fb_username")
String fbUserName;
#SerializedName("featured")
private List<EntityFeaturedResponse> featured;
#SerializedName("collections")
List<Collections> collectionsList;
public Integer getEntityID() {
return entityID;
}
public String getEntityName() {
return entityName;
}
public String getEntityDescription() {
return entityDescription;
}
public String getEntityImageURL() {
return entityImageURL;
}
public String getEntitySquareURL() {
return entitySquareURL;
}
public String getEntitySlug() {
return entitySlug;
}
public boolean isEntityLive() {
return isEntityLive;
}
public String getTwitterUserName() {
return twitterUserName;
}
public String getFbUserName() {
return fbUserName;
}
public List<EntityFeaturedResponse> getFeatured() {
return featured;
}
public List<Collections> getCollectionsList() {
return collectionsList;
}
public static class Collections {
#SerializedName("type")
String type;
#SerializedName("type_id")
Integer typeID;
//Data sometimes contains JSON object and sometimes it contains JSON Array
#SerializedName("data")
List<Data> data;
public String getType() {
return type;
}
public Integer getTypeID() {
return typeID;
}
public List<Data> getData() {
return data;
}
public static class Data {
#SerializedName("view_all")
boolean viewAll;
#SerializedName("title")
String title;
public boolean isViewAll() {
return viewAll;
}
public String getTitle() {
return title;
}
}
}
}
}
ArrayAdapterFactory.java
public class ArrayAdapterFactory implements TypeAdapterFactory {
#SuppressWarnings({"unchecked"})
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
ArrayAdapter typeAdapter = null;
try {
if (type.getRawType() == List.class) {
typeAdapter = new ArrayAdapter(
(Class) ((ParameterizedType) type.getType())
.getActualTypeArguments()[0]);
}
} catch (Exception e) {
e.printStackTrace();
}
return typeAdapter;
}
public class ArrayAdapter<T> extends TypeAdapter<List<T>> {
private Class<T> adapterClass;
public ArrayAdapter(Class<T> adapterClass) {
this.adapterClass = adapterClass;
}
public List<T> read(JsonReader reader) throws IOException {
List<T> list = new ArrayList<T>();
Gson gson = new Gson();
if (reader.peek() == JsonToken.BEGIN_OBJECT) {
T inning = (T) gson.fromJson(reader, adapterClass);
list.add(inning);
} else if (reader.peek() == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
while (reader.hasNext()) {
//read(reader);
T inning = (T) gson.fromJson(reader, adapterClass);
list.add(inning);
}
reader.endArray();
} else {
reader.skipValue();
}
return list;
}
public void write(JsonWriter writer, List<T> value) throws IOException {
}
}
}
As complete API response is very large, I am providing a link to .json file. https://drive.google.com/open?id=1RMOiM7UjOwR-5b0Ik7ymy65ZOhc8I8hY
UPDATE:
I tried the solution which is mentioned below but still, DataType1 and DataType2 both are coming nulls. Although I am no longer getting the GSON exception.
public class EntityDetailResponseV2 {
#SerializedName("results")
private Results results;
#SerializedName("success")
private boolean success;
public static EntityDetailResponseV2 getObject(String res) {
try {
Gson gson = new GsonBuilder().registerTypeAdapter(Collections.class, new Results.Collections.CollectionItemDeserializer()).create();
return gson.fromJson(res, EntityDetailResponseV2.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Results getResults() {
return results;
}
public boolean isSuccess() {
return success;
}
public static class Results {
#SerializedName("id")
Integer entityID;
#SerializedName("name")
String entityName;
#SerializedName("description")
String entityDescription;
#SerializedName("image_url")
String entityImageURL;
#SerializedName("square_entity_url")
String entitySquareURL;
#SerializedName("slug")
String entitySlug;
#SerializedName("live")
boolean isEntityLive;
#SerializedName("twitter_username")
String twitterUserName;
#SerializedName("fb_username")
String fbUserName;
#SerializedName("featured")
private List<EntityFeaturedResponse> featured;
#SerializedName("collections")
List<Collections> collectionsList;
public Integer getEntityID() {
return entityID;
}
public String getEntityName() {
return entityName;
}
public String getEntityDescription() {
return entityDescription;
}
public String getEntityImageURL() {
return entityImageURL;
}
public String getEntitySquareURL() {
return entitySquareURL;
}
public String getEntitySlug() {
return entitySlug;
}
public boolean isEntityLive() {
return isEntityLive;
}
public String getTwitterUserName() {
return twitterUserName;
}
public String getFbUserName() {
return fbUserName;
}
public List<EntityFeaturedResponse> getFeatured() {
return featured;
}
public List<Collections> getCollectionsList() {
return collectionsList;
}
public static class Collections {
#SerializedName("type")
String type;
#SerializedName("order")
Integer order;
#SerializedName("type_id")
Integer typeId;
DataType1 dataType1;
List<DataType2> dataType2;
public String getType() {
return type;
}
public Integer getOrder() {
return order;
}
public Integer getTypeId() {
return typeId;
}
public DataType1 getDataType1() {
return dataType1;
}
public List<DataType2> getDataType2() {
return dataType2;
}
public static class CollectionItemDeserializer implements JsonDeserializer<Collections> {
#Override
public Collections deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Collections collectionItem = new Gson().fromJson(json, Collections.class);
JsonObject jsonObject = json.getAsJsonObject();
if (collectionItem.getType() != null) {
JsonElement element = jsonObject.get("data");
switch (collectionItem.getTypeId()) {
case AppConstants.ENTITY_SHOP:
case AppConstants.ENTITY_MEDIA_COLLECTION:
case AppConstants.ENTITY_ECOM_COLLECTION:
case AppConstants.ENTITY_BANNER:
collectionItem.dataType1 = new Gson().fromJson(element, DataType1.class);
break;
case AppConstants.ENTITY_TOP_AUDIOS:
case AppConstants.ENTITY_TOP_VIDEOS:
case AppConstants.ENTITY_LATEST_VIDEOS:
case AppConstants.ENTITY_TOP_PLAYLISTS:
case AppConstants.ENTITY_WALLPAPERS:
case AppConstants.ENTITY_QUOTATIONS:
List<DataType2> values = new Gson().fromJson(element, new TypeToken<ArrayList<DataType2>>() {}.getType());
collectionItem.dataType2 = values;
break;
}
}
return collectionItem;
}
}
public static class DataType1 {
#SerializedName("view_all")
boolean viewAll;
public boolean isViewAll() {
return viewAll;
}
}
public static class DataType2 {
#SerializedName("view_all")
boolean viewAll;
public boolean isViewAll() {
return viewAll;
}
}
}
}
}
You need to use a custom JsonDeserializer. Here's the solution :
public class CollectionListItem {
#SerializedName ("type")
String type;
#SerializedName ("order")
Integer order;
#SerializedName ("id")
Integer id;
#SerializedName ("type_id")
Integer typeId;
DataType1 dataType1;
List<DataType2> dataType2;
List<DataType3> dataType3;
final static String DATA_TYPE_1 = "SHOP";
final static String DATA_TYPE_2 = "TOP_AUDIOS";
final static String DATA_TYPE_3 = "MEDIA_COLLECTION";
//Public getters and setters
public static class CollectionItemDeserializer implements JsonDeserializer<CollectionListItem> {
#Override
public CollectionListItem deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
CollectionListItem collectionItem = new Gson().fromJson(json, CollectionListItem.class);
JsonObject jsonObject = json.getAsJsonObject();
if (collectionItem.getType() != null) {
JsonElement element = jsonObject.get("data");
switch(collectionItem.getType()){
case CollectionListItem.DATA_TYPE_1 :
collectionItem.dataType1 = new Gson().fromJson(element, DataType1.class);
break;
case CollectionListItem.DATA_TYPE_2:
List<DataType2> values = new Gson().fromJson(element, new TypeToken<ArrayList<DataType2>>() {}.getType());
collectionItem.dataType2 = values;
break;
case CollectionListItem.DATA_TYPE_3:
List<DataType3> values_ = new Gson().fromJson(element, new TypeToken<ArrayList<DataType3>>() {}.getType());
collectionItem.dataType3 = values_;
break;
}
}
return collectionItem;
}
}
}
DataType1, DataType2, etc are the individual classes for different responses.
Also, add this line to register your custom deserializer with gson
Gson gson = new GsonBuilder()
.registerTypeAdapter(CollectionListItem.class,
new CollectionListItem.CollectionItemDeserializer())
.create();

unable to convert json string to POJO due to error Expected a string but was BEGIN_ARRAY

For some reason i am not able to covert it to a POJO. The call i am making and have tried is like this:
NewsEntities newsEntities = new Gson().fromJson(jsonString, NewsEntities.class);
The mystery is that the json is not in an array. its a jsonObject i think.
the jsonString is here
The error i get in android is:
Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 1006 path $.results[0].org_facet
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err: at com.google.gson.stream.JsonReader.nextString(JsonReader.java:831)
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err: at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:422)
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err: at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:410)
02-24 23:42:49.955 15463-15531/news.myapp.com.technewssample W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
02-24 23:42:49.956 15463-15531/news.myapp.com.technewssample W/System.err: at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(Reflect
the newsEntities class itself looks like this and i simply made it from http://www.jsonschema2pojo.org/:
public class NewsEntities implements Parcelable
{
#SerializedName("status")
#Expose
private String status;
#SerializedName("copyright")
#Expose
private String copyright;
#SerializedName("section")
#Expose
private String section;
#SerializedName("last_updated")
#Expose
private String lastUpdated;
#SerializedName("num_results")
#Expose
private Integer numResults;
#SerializedName("results")
#Expose
private List<Result> results = null;
public final static Parcelable.Creator<NewsEntities> CREATOR = new Creator<NewsEntities>() {
#SuppressWarnings({
"unchecked"
})
public NewsEntities createFromParcel(Parcel in) {
NewsEntities instance = new NewsEntities();
instance.status = ((String) in.readValue((String.class.getClassLoader())));
instance.copyright = ((String) in.readValue((String.class.getClassLoader())));
instance.section = ((String) in.readValue((String.class.getClassLoader())));
instance.lastUpdated = ((String) in.readValue((String.class.getClassLoader())));
instance.numResults = ((Integer) in.readValue((Integer.class.getClassLoader())));
in.readList(instance.results, (Result.class.getClassLoader()));
return instance;
}
public NewsEntities[] newArray(int size) {
return (new NewsEntities[size]);
}
}
;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCopyright() {
return copyright;
}
public void setCopyright(String copyright) {
this.copyright = copyright;
}
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
public String getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(String lastUpdated) {
this.lastUpdated = lastUpdated;
}
public Integer getNumResults() {
return numResults;
}
public void setNumResults(Integer numResults) {
this.numResults = numResults;
}
public List<Result> getResults() {
return results;
}
public void setResults(List<Result> results) {
this.results = results;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(status);
dest.writeValue(copyright);
dest.writeValue(section);
dest.writeValue(lastUpdated);
dest.writeValue(numResults);
dest.writeList(results);
}
public int describeContents() {
return 0;
}
}
UPDATE: HERE IS THE RESULT CLASS:
public class Result implements Parcelable
{
#SerializedName("section")
#Expose
private String section;
#SerializedName("subsection")
#Expose
private String subsection;
#SerializedName("title")
#Expose
private String title;
#SerializedName("abstract")
#Expose
private String _abstract;
#SerializedName("url")
#Expose
private String url;
#SerializedName("byline")
#Expose
private String byline;
#SerializedName("item_type")
#Expose
private String itemType;
#SerializedName("updated_date")
#Expose
private String updatedDate;
#SerializedName("created_date")
#Expose
private String createdDate;
#SerializedName("published_date")
#Expose
private String publishedDate;
#SerializedName("material_type_facet")
#Expose
private String materialTypeFacet;
#SerializedName("kicker")
#Expose
private String kicker;
#SerializedName("des_facet")
#Expose
private List<String> desFacet = null;
#SerializedName("org_facet")
#Expose
private String orgFacet;
#SerializedName("per_facet")
#Expose
private String perFacet;
#SerializedName("geo_facet")
#Expose
private List<String> geoFacet = null;
#SerializedName("multimedia")
#Expose
private List<Multimedium> multimedia = null;
public final static Parcelable.Creator<Result> CREATOR = new Creator<Result>() {
#SuppressWarnings({
"unchecked"
})
public Result createFromParcel(Parcel in) {
Result instance = new Result();
instance.section = ((String) in.readValue((String.class.getClassLoader())));
instance.subsection = ((String) in.readValue((String.class.getClassLoader())));
instance.title = ((String) in.readValue((String.class.getClassLoader())));
instance._abstract = ((String) in.readValue((String.class.getClassLoader())));
instance.url = ((String) in.readValue((String.class.getClassLoader())));
instance.byline = ((String) in.readValue((String.class.getClassLoader())));
instance.itemType = ((String) in.readValue((String.class.getClassLoader())));
instance.updatedDate = ((String) in.readValue((String.class.getClassLoader())));
instance.createdDate = ((String) in.readValue((String.class.getClassLoader())));
instance.publishedDate = ((String) in.readValue((String.class.getClassLoader())));
instance.materialTypeFacet = ((String) in.readValue((String.class.getClassLoader())));
instance.kicker = ((String) in.readValue((String.class.getClassLoader())));
in.readList(instance.desFacet, (java.lang.String.class.getClassLoader()));
instance.orgFacet = ((String) in.readValue((String.class.getClassLoader())));
instance.perFacet = ((String) in.readValue((String.class.getClassLoader())));
in.readList(instance.geoFacet, (java.lang.String.class.getClassLoader()));
in.readList(instance.multimedia, (Multimedium.class.getClassLoader()));
return instance;
}
public Result[] newArray(int size) {
return (new Result[size]);
}
}
;
public String getSection() {
return section;
}
public void setSection(String section) {
this.section = section;
}
public String getSubsection() {
return subsection;
}
public void setSubsection(String subsection) {
this.subsection = subsection;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAbstract() {
return _abstract;
}
public void setAbstract(String _abstract) {
this._abstract = _abstract;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getByline() {
return byline;
}
public void setByline(String byline) {
this.byline = byline;
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getUpdatedDate() {
return updatedDate;
}
public void setUpdatedDate(String updatedDate) {
this.updatedDate = updatedDate;
}
public String getCreatedDate() {
return createdDate;
}
public void setCreatedDate(String createdDate) {
this.createdDate = createdDate;
}
public String getPublishedDate() {
return publishedDate;
}
public void setPublishedDate(String publishedDate) {
this.publishedDate = publishedDate;
}
public String getMaterialTypeFacet() {
return materialTypeFacet;
}
public void setMaterialTypeFacet(String materialTypeFacet) {
this.materialTypeFacet = materialTypeFacet;
}
public String getKicker() {
return kicker;
}
public void setKicker(String kicker) {
this.kicker = kicker;
}
public List<String> getDesFacet() {
return desFacet;
}
public void setDesFacet(List<String> desFacet) {
this.desFacet = desFacet;
}
public String getOrgFacet() {
return orgFacet;
}
public void setOrgFacet(String orgFacet) {
this.orgFacet = orgFacet;
}
public String getPerFacet() {
return perFacet;
}
public void setPerFacet(String perFacet) {
this.perFacet = perFacet;
}
public List<String> getGeoFacet() {
return geoFacet;
}
public void setGeoFacet(List<String> geoFacet) {
this.geoFacet = geoFacet;
}
public List<Multimedium> getMultimedia() {
return multimedia;
}
public void setMultimedia(List<Multimedium> multimedia) {
this.multimedia = multimedia;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(section);
dest.writeValue(subsection);
dest.writeValue(title);
dest.writeValue(_abstract);
dest.writeValue(url);
dest.writeValue(byline);
dest.writeValue(itemType);
dest.writeValue(updatedDate);
dest.writeValue(createdDate);
dest.writeValue(publishedDate);
dest.writeValue(materialTypeFacet);
dest.writeValue(kicker);
dest.writeList(desFacet);
dest.writeValue(orgFacet);
dest.writeValue(perFacet);
dest.writeList(geoFacet);
dest.writeList(multimedia);
}
public int describeContents() {
return 0;
}
}
Automatic POJO generators may generate wrong mappings in some cases, especially if mapped fields are polymorphic or use non-standard approaches for whatever reasons. According to the error you're getting, your mapping expects a String but the JSON has an array at that place. In your case, $.results[0].org_facet points to:
...,"org_facet":["Amazon.com Inc","Cravath Swaine \u0026 Moore"],...
// ^____here
If you change the mapping String orgFacet to List<String> orgFacet, you'll get similar errors for another fields like perFacet or multimedia (there are some more around). Since those fields are meant to be lists and "" is just a marker for an empty array [] or null, Gson cannot handle it itself because of such a message format. However, you can make it work with such fields writing a custom type adapter that would be applicable for all lists deserialized using a single Gson instance.
final class ArrayOrEmptyStringTypeAdapter<E>
extends TypeAdapter<List<E>> {
private final Gson gson;
private final Type elementType;
private ArrayOrEmptyStringTypeAdapter(final Gson gson, final Type elementType) {
this.gson = gson;
this.elementType = elementType;
}
static <E> TypeAdapter<List<E>> getArrayOrEmptyStringTypeAdapter(final Gson gson, final Type elementType) {
return new ArrayOrEmptyStringTypeAdapter<>(gson, elementType);
}
#Override
public void write(final JsonWriter out, final List<E> list) {
throw new UnsupportedOperationException();
}
#Override
public List<E> read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek(); // Peek the next token
switch ( token ) {
case BEGIN_ARRAY: // If it's an array begin `[`, then parse it as an array
return parseAsArray(in);
case STRING: // Or if it's a string, parse it in another way
return parseAsString(in);
default:
throw new MalformedJsonException("Unexpected token: " + token);
}
}
private List<E> parseAsArray(final JsonReader in)
throws IOException {
final List<E> list = new ArrayList<>();
in.beginArray(); // Consume `[` from the token stream
while ( in.peek() != END_ARRAY ) {
final E element = gson.fromJson(in, elementType); // Delegate downstream parsing to the Gson instance
list.add(element);
}
in.endArray(); // Consume `]` from the token stream
return list;
}
private List<E> parseAsString(final JsonReader in)
throws IOException {
in.skipValue(); // in.nextString() consumes more memory accumulating the result
return new ArrayList<>(); // Or null -- up to you. Or even Collections.emptyList(), but Gson uses mutable lists so we do
}
}
The next thing is binding the type adapter and a Gson instance via a type adapter factory:
final class ArrayOrEmptyStringTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory arrayOrEmptyStringTypeAdapterFactory = new ArrayOrEmptyStringTypeAdapterFactory();
private ArrayOrEmptyStringTypeAdapterFactory() {
}
static TypeAdapterFactory getArrayOrEmptyStringTypeAdapterFactory() {
return arrayOrEmptyStringTypeAdapterFactory;
}
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( List.class.isAssignableFrom(typeToken.getRawType()) ) { // Is it an instance of java.util.List? Not that getRawType() and getType() have different purposes
final TypeAdapter<List<Object>> typeAdapter = getArrayOrEmptyStringTypeAdapter(gson, getListElementType(typeToken.getType()));
#SuppressWarnings("unchecked")
final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) typeAdapter;
return castTypeAdapter;
}
return null;
}
private static Type getListElementType(final Type type) {
return type instanceof ParameterizedType // Is it a generic type with type parameters?
? ((ParameterizedType) type).getActualTypeArguments()[0] // If yes, then we know that java.util.List has one type paremeter only
: Object.class; // Otherwise it's a raw list, and no element type info is provided
}
}
How it's used:
private static final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(getArrayOrEmptyStringTypeAdapterFactory())
.create();
final NewsEntities newEntities = gson.fromJson(jsonString, NewsEntities.class);
System.out.println(newEntities.results.get(0).orgFacet);
System.out.println(newEntities.results.get(0).perFacet)
The output:
[Amazon.com Inc, Cravath Swaine & Moore]
[Bezos, Jeffrey P]
You haven't attached your result class but it looks to me like your result class has a string field instead of an array in org_facet. But it would be easier to answer if you add your Result class.

Parsing JSON in Android, not getting value

I am able to parse everything i need, except for the target_id's in the field_exercis_arc. I get the nid, title and body. Not sure how to get the id's in the field_exercis_arc.
The JSON
[{
"nid": "26",
"title": "Question test",
"body": "xcvxcv",
"field_exercis_arc": ["25","27"]
}]
The Code
String finalJson = buffer.toString();
JSONArray parentArray = new JSONArray(finalJson);
List<ExerciseModel> exerciseModelList = new ArrayList<>();
for(int i=0; i<parentArray.length(); i++){
JSONObject finalObject = parentArray.getJSONObject(i);
title_exi = finalObject.getString("title");
text_exi = finalObject.getString("body");
//This part is working.
ExerciseModel exerciseModel = new ExerciseModel();
exerciseModel.setTitle(finalObject.getString("title"));
exerciseModel.setNid(finalObject.getInt("nid"));
exerciseModel.setBody(finalObject.getString("body"));
//Problem with this part, not getting the target_id's.
List<ExerciseModel.Exer> exerList = new ArrayList<>();
for(int j=0; j<finalObject.getJSONArray("field_exercis_arc").length(); j++){
ExerciseModel.Exer exercis = new ExerciseModel.Exer();
exercis.setTarget_id(finalObject.getJSONArray("field_exercis_arc").getJSONObject(j).getString("target_id"));
exerList.add(exercis);
}
exerciseModel.setExerList(exerList);
exerciseModelList.add(exerciseModel);
mDB.saveRecordEX(exerciseModel);
}
The model for the field_exercis_arc and target_id's fields
private List<Exer> exerList;
public List<Exer> getExerList() {
return exerList;
}
public void setExerList(List<Exer> exerList) {
this.exerList = exerList;
}
public static class Exer{
private String target_id;
public String getTarget_id() {
return target_id;
}
public void setTarget_id(String target_id) {
this.target_id = target_id;
}
}
Thanks in advance
I recommend you to use GSON library to get result from JSON. For that you will need Java class in order to parse result to object. For this you can use JSON to Java Class conversion here.
For you example classes would be:
public class Und
{
private String value;
public String getValue() { return this.value; }
public void setValue(String value) { this.value = value; }
}
public class Body
{
private ArrayList<Und> und;
public ArrayList<Und> getUnd() { return this.und; }
public void setUnd(ArrayList<Und> und) { this.und = und; }
}
public class Und2
{
private String target_id;
public String getTargetId() { return this.target_id; }
public void setTargetId(String target_id) { this.target_id = target_id; }
}
public class FieldExercisArc
{
private ArrayList<Und2> und;
public ArrayList<Und2> getUnd() { return this.und; }
public void setUnd(ArrayList<Und2> und) { this.und = und; }
}
public class RootObject
{
private String vid;
public String getVid() { return this.vid; }
public void setVid(String vid) { this.vid = vid; }
private String uid;
public String getUid() { return this.uid; }
public void setUid(String uid) { this.uid = uid; }
private String title;
public String getTitle() { return this.title; }
public void setTitle(String title) { this.title = title; }
private Body body;
public Body getBody() { return this.body; }
public void setBody(Body body) { this.body = body; }
private FieldExercisArc field_exercis_arc;
public FieldExercisArc getFieldExercisArc() { return this.field_exercis_arc; }
public void setFieldExercisArc(FieldExercisArc field_exercis_arc) { this.field_exercis_arc = field_exercis_arc; }
private String cid;
public String getCid() { return this.cid; }
public void setCid(String cid) { this.cid = cid; }
private String last_comment_timestamp;
public String getLastCommentTimestamp() { return this.last_comment_timestamp; }
public void setLastCommentTimestamp(String last_comment_timestamp) { this.last_comment_timestamp = last_comment_timestamp; }
}
You can convert result to RootObject. Fox example:
String json = "{\"vid\": \"26\",\"uid\": \"1\",\"title\": \"Question test\",\"body\": {\"und\": [{\"value\": \"xcvxcv\"}]},\"field_exercis_arc\": {\"und\": [{\"target_id\": \"25\"},{\"target_id\":\"27\"}]},\"cid\": \"0\",\"last_comment_timestamp\": \"1472217577\"}";
RootObject object = new Gson().fromJson(json, RootObject.class);
System.out.println("Title is: "+object.getTitle() );
Result is:
Title is: Question test
After this you can use your object to get any value from your JSON.
Also you should know that your JSON is not valid. You have commas on two places that should not exists. In string i gave you above those are fixed. You should check you JSON with: JSON Formatter
Use below code :
exercis.setTarget_id(finalObject.getJSONArray("field_exercis_arc").getString(j));
JsonArray fieldArray=yourJsonObject.getJsonArray("field_exercis_arc");
for(int i=0;i<fieldArray.length;i++){
fieldArray.getString(i);
}
TO the parse the JSON you have to do it like this.
String finalJson = buffer.toString();
JSONArray parentArray = new JSONArray(finalJson);
for(int i=0; i<parentArray.length(); i++){
JSONObject finalObject = parentArray.getJSONObject(i);
String title = finalObject.getString("title");
String body = finalObject.getString("body");
JSONArray arr = finalObject.getJSONArray("field_exercis_arc");
for(int x=0; x < arr.length(); x++){
String val = arr.getString(x);
}
}

JSON to POJO conversion error for different types of values

While converting JSON data to POJO using Gson I get this error.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING
at line 1 column 119
My JSON is :
{
"success":true,
"result":[
{
"htmlId":"edit_text_1",
"value":"3",
"contentType":"Snippet"
},
{
"htmlId":"edit_text_2",
"value":[
{
"type":"HTML",
"value":"<ul>\n<li>This is a text from the static editable content.</li>\n</ul>"
},
{
"type":"Text",
"value":"- This is a text from the static editable content."
} ],
"contentType":"Text"
}
]
}
for each result the value type may differ. Sometimes it is a string value or an array.
Here's my pojo for results:
private String htmlId;
private Object value = new ArrayList<Object>();
private String contentType;
public String getHtmlId() {
return htmlId;
}
public void setHtmlId(String htmlId) {
this.htmlId = htmlId;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
if(value instanceof String)
this.value = (List<String>)value;
else if(value instanceof ArrayList)
this.value = (ArrayList<MarketoTypeValue>)value;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
When there is no snippet type in the result, my code works fine.
Tried with typecast, that did not help me either.
What can be the best way to handle such scenario?
First define a value class
class Value {
private String type;
private String value;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Then update your big root pojo
class Pojo {
private String htmlId;
private Collection<Value> valuea;
private String contentType;
public String getHtmlId() {
return htmlId;
}
public void setHtmlId(String htmlId) {
this.htmlId = htmlId;
}
public Collection<Value> getValuea() {
return valuea;
}
public void setValuea(Collection<Value> valuea) {
this.valuea = valuea;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}
And convert it using Gson
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
final Collection<Pojo> collection = gson.fromJson(json, Collection.class);

Categories