I am trying to assign the value returned by some function to a field in the deserialized class of json.
FileInfo.java
public class FileInfo {
#SerializedName("Name")
private String mName;
#SerializedName("Url")
private String mUri;
#SerializedName("Size")
private Integer mSize;
#SerializedName("ModTime")
private Long mModifiedTime;
private FileType mType;
#SerializedName("Children")
private ArrayList<FileInfo> mChildren = new ArrayList<>();
public ArrayList<FileInfo> getChildren() {
return mChildren;
}
public long getModifiedTime() {
return mModifiedTime;
}
public String getName() {
return mName;
}
public Integer getSize() {
return mSize;
}
public String getUrl() {
return mUri;
}
public FileType getType() {
return mType;
}
public void setChildren(ArrayList<FileInfo> mChildren) {
this.mChildren = mChildren;
}
public void setModifiedTime(long mModifiedTime) {
this.mModifiedTime = mModifiedTime;
}
public void setName(String mName) {
this.mName = mName;
}
public void setSize(Integer mSize) {
this.mSize = mSize;
}
public void setType(FileType mType) {
this.mType = mType;
}
public void setUri(String mUri) {
this.mUri = mUri;
}
#Override
public String toString() {
return FileInfo.class.toString();
}
public FileInfo() {
}
}
The mType needs to be assigned to foo(mName). I looked up custom deserializers and instance creators but none of those helped. I also thought of TypeAdapters which i feel defeats the purpose of keeping deserialization(using GSON) simple.
This is a sample JSON string that will be deserialized.
[
{
"Name":"Airport",
"Url":"http://192.168.2.2/api/sites/Baltimore%20Airport/Airport",
"Size":0,
"ModTime":"2015-12-02T14:19:17.29824-05:00",
"Children":null
}
]
P.S. I'm not sure if this should be done during deserialization but trying anyways. Also please let me know of alternative ways to achieve this.
Related
I am trying to parse the JSON result from the Wordpress plugins API using Retrofit2 and GSON. I have generated my POJO using the well known website and modified it into the following model:
PluginsApiResponse.java
public class PluginsApiResponse {
#SerializedName("plugins")
#Expose
private List<Plugin> plugins = null;
public List<Plugin> getPlugins() {
return plugins;
}
public void setPlugins(List<Plugin> plugins) {
this.plugins = plugins;
}
}
Plugin.java
public class Plugin {
#SerializedName("name")
#Expose
private String name;
#SerializedName("homepage")
#Expose
private String homepage;
#SerializedName("screenshots")
#Expose
private Screenshots screenshots;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHomepage() {
return homepage;
}
public void setHomepage(String homepage) {
this.homepage = homepage;
}
public Screenshots getScreenshots() {
return screenshots;
}
public void setScreenshots(Screenshots screenshots) {
this.screenshots = screenshots;
}
}
Screenshots.java
public class Screenshots {
#SerializedName("1")
#Expose
private com.dkalsan.retrofitwordpress._1 _1;
#SerializedName("2")
#Expose
private com.dkalsan.retrofitwordpress._2 _2;
#SerializedName("3")
#Expose
private com.dkalsan.retrofitwordpress._3 _3;
public com.dkalsan.retrofitwordpress._1 get1() {
return _1;
}
public void set1(com.dkalsan.retrofitwordpress._1 _1) {
this._1 = _1;
}
public com.dkalsan.retrofitwordpress._2 get2() {
return _2;
}
public void set2(com.dkalsan.retrofitwordpress._2 _2) {
this._2 = _2;
}
public com.dkalsan.retrofitwordpress._3 get3() {
return _3;
}
public void set3(com.dkalsan.retrofitwordpress._3 _3) {
this._3 = _3;
}
}
_1.java (_2.java and _3.java are identical)
public class _1 {
#SerializedName("src")
#Expose
private String src;
#SerializedName("caption")
#Expose
private String caption;
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
}
The problem occurs in case the screenshots field contains no entries. I've set up the HttpLoggingInterceptor, which logs the response code 200 and the json in its entirety. I've also excluded the possibility of it being the internet connectivity issue according to the following article. If I remove the screenshots field from the model there is no trouble parsing. Is it possible that the error persists due to GSON trying to deserialize the nonexistent fields 1, 2, and 3 and if so, how to deal with it?
Turn out the problem was in the JSON response formatting. If there were no screenshots it was formatted as a JSON array, otherwise it was formatted as a JSON object containing objects 1, 2, 3, etc. I've managed to fix it by following the answer on this stackoverflow question.
I starting out with RxJava and Retrofit and wanted to create a simple app to show a list of 100 cryptocurrencies.
I am making an api call which results in something like this :
{
"Response": "Success",
"Message": "Coin list succesfully returned!",
"BaseImageUrl": "https://www.cryptocompare.com",
"BaseLinkUrl": "https://www.cryptocompare.com",
"Data": {
"LTC": {
"Id": "3808",
"Url": "/coins/ltc/overview",
"ImageUrl": "/media/19782/ltc.png",
"Name": "LTC",
"CoinName": "Litecoin",
"FullName": "Litecoin (LTC)",
"Algorithm": "Scrypt",
"ProofType": "PoW",
"SortOrder": "2"
}
...
},
"Type": 100
}
But all I want from this is "Response" and "Data". Since it is not practical to create a 100 different model classes for each coin, I want to store information of all the coins in a common class named Coin which would look something like this :
public class Coins {
#SerializedName("Algorithm")
private String mAlgorithm;
#SerializedName("CoinName")
private String mCoinName;
#SerializedName("FullName")
private String mFullName;
#SerializedName("FullyPremined")
private String mFullyPremined;
#SerializedName("Id")
private String mId;
#SerializedName("ImageUrl")
private String mImageUrl;
#SerializedName("Name")
private String mName;
#SerializedName("PreMinedValue")
private String mPreMinedValue;
#SerializedName("ProofType")
private String mProofType;
#SerializedName("SortOrder")
private String mSortOrder;
#SerializedName("Sponsored")
private Boolean mSponsored;
#SerializedName("Symbol")
private String mSymbol;
#SerializedName("TotalCoinSupply")
private String mTotalCoinSupply;
#SerializedName("TotalCoinsFreeFloat")
private String mTotalCoinsFreeFloat;
#SerializedName("Url")
private String mUrl;
public String getAlgorithm() {
return mAlgorithm;
}
public void setAlgorithm(String Algorithm) {
mAlgorithm = Algorithm;
}
public String getCoinName() {
return mCoinName;
}
public void setCoinName(String CoinName) {
mCoinName = CoinName;
}
public String getFullName() {
return mFullName;
}
public void setFullName(String FullName) {
mFullName = FullName;
}
public String getFullyPremined() {
return mFullyPremined;
}
public void setFullyPremined(String FullyPremined) {
mFullyPremined = FullyPremined;
}
public String getId() {
return mId;
}
public void setId(String Id) {
mId = Id;
}
public String getImageUrl() {
return mImageUrl;
}
public void setImageUrl(String ImageUrl) {
mImageUrl = ImageUrl;
}
public String getName() {
return mName;
}
public void setName(String Name) {
mName = Name;
}
public String getPreMinedValue() {
return mPreMinedValue;
}
public void setPreMinedValue(String PreMinedValue) {
mPreMinedValue = PreMinedValue;
}
public String getProofType() {
return mProofType;
}
public void setProofType(String ProofType) {
mProofType = ProofType;
}
public String getSortOrder() {
return mSortOrder;
}
public void setSortOrder(String SortOrder) {
mSortOrder = SortOrder;
}
public Boolean getSponsored() {
return mSponsored;
}
public void setSponsored(Boolean Sponsored) {
mSponsored = Sponsored;
}
public String getSymbol() {
return mSymbol;
}
public void setSymbol(String Symbol) {
mSymbol = Symbol;
}
public String getTotalCoinSupply() {
return mTotalCoinSupply;
}
public void setTotalCoinSupply(String TotalCoinSupply) {
mTotalCoinSupply = TotalCoinSupply;
}
public String getTotalCoinsFreeFloat() {
return mTotalCoinsFreeFloat;
}
public void setTotalCoinsFreeFloat(String TotalCoinsFreeFloat) {
mTotalCoinsFreeFloat = TotalCoinsFreeFloat;
}
public String getUrl() {
return mUrl;
}
public void setUrl(String Url) {
mUrl = Url;
}
}
So finally my mapped response class would look like :
public class CoinsListResponse {
private boolean success;
private List<Coins> coinsList;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public List<Coins> getCoinsList() {
return coinsList;
}
public void setCoinsList(List<Coins> coinsList) {
this.coinsList = coinsList;
}
}
I haven't added #Serialized notations because I don't know what key to annotate it with.
My Retrofit service interface has a method to return the results to this map :
public interface CoinService {
#NonNull
#POST
Observable<CoinsListResponse> getCoinList();
}
Since, I am a starter with Retrofit and RxAndroid, there might be a better method to do this, which I am not aware of. If so, please mention that as well !! I am trying to get my head around this for days but couldn't find any answer on SO as well.
Please Help !!
Change
private List<Coins> coinsList;
to
#SerializedName("Data")
private Map<String, Coins> coinsByName;
You can then either just use coinsByName.values() or call e.g. coinsByName.get("LTC")
I'm trying to store a coordnates (array of double) using Realm-java,but I'm not able to do it.
Here is an example of json that I'm trying to parse:
{"_id":"597cd98b3af0b6315576d717",
"comarca":"string",
"font":null,
"imatge":"string",
"location":{
"coordinates":[41.64642,1.1393],
"type":"Point"
},
"marca":"string",
"municipi":"string",
"publisher":"string",
"recursurl":"string",
"tematica":"string",
"titol":"string"
}
My global object code is like that
public class Images extends RealmObject implements Serializable {
#PrimaryKey
private String _id;
private String recursurl;
private String titol;
private String municipi;
private String comarca;
private String marca;
private String imatge;
#Nullable
private Location location;
private String tematica;
private String font;
private String parentRoute;
public Location getLocation() {return location;}
public void setLocation(Location location) {this.location = location;}
public String getParentRoute() {
return parentRoute;
}
public void setParentRoute(String parentRoute) {
this.parentRoute = parentRoute;
}
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getFont() {
return font;
}
public void setFont(String font) {
this.font = font;
}
public String getRecursurl() {
return recursurl;
}
public void setRecursurl(String recursurl) {
this.recursurl = recursurl;
}
public String getTitol() {
return titol;
}
public void setTitol(String titol) {
this.titol = titol;
}
public String getMunicipi() {
return municipi;
}
public void setMunicipi(String municipi) {
this.municipi = municipi;
}
public String getComarca() {
return comarca;
}
public void setComarca(String comarca) {
this.comarca = comarca;
}
public String getMarca() {
return marca;
}
public void setMarca(String marca) {
this.marca = marca;
}
public String getImatge() {
return imatge;
}
public void setImatge(String imatge) {
this.imatge = imatge;
}
public String getTematica() {
return tematica;
}
public void setTematica(String tematica) {
this.tematica = tematica;
}
And Location is a composite of type and a realmlist
Location.java
public class Location extends RealmObject implements Serializable {
private String type;
private RealmList<RealmDoubleObject> coordinates;
public Location() {
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public RealmList<RealmDoubleObject> getCoordinates() {
return coordinates;
}
public void setCoordinates(RealmList<RealmDoubleObject> coordinates) {
this.coordinates = coordinates;
}
}
RealmDoubleObject.java
public class RealmDoubleObject extends RealmObject implements Serializable{
private Double value;
public RealmDoubleObject() {
}
public Double getDoublevalue() {
return value;
}
public void setDoublevalue(Double value) {
this.value = value;
}
}
The error is com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at path $[0].location.coordinates[0] but I'm not able to figure out why this number is not "fitting" by RealmDoubleObject.
For those that not familiar with realm RealmList doesn't work and you have to build your own realm object.
Thank you. I hope to find some Realm experts here!
SOLVED:
using Gson deserializer it can be done
First we have to initialize the gson object like this
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.registerTypeAdapter(new TypeToken<RealmList<RealmDoubleObject>>() {}.getType(), new TypeAdapter<RealmList<RealmDoubleObject>>() {
#Override
public void write(JsonWriter out, RealmList<RealmDoubleObject> value) throws IOException {
// Ignore
}
#Override
public RealmList<RealmDoubleObject> read(JsonReader in) throws IOException {
RealmList<RealmDoubleObject> list = new RealmList<RealmDoubleObject>();
in.beginArray();
while (in.hasNext()) {
Double valor = in.nextDouble();
list.add(new RealmDoubleObject(valor));
}
in.endArray();
return list;
}
})
.create();
And then we have to put some other constructor method
public RealmDoubleObject(double v) {
this.value = v;
}
and this is all.
Thanks for the help #EpicPandaForce
I am very new to JSON and jackson, currently I have pojo files and I am trying to get the data and store it in an array. for example I want to extract Network name and store it an array and later display or compare it with live site data.
here is the main pojo file -
public class JsonGen{
private String _type;
private List cast;
private List clips;
private Common_sense_data common_sense_data;
private String common_sense_id;
private List crew;
private String description;
private List episodes;
private Number franchise_id;
private List genres;
private String guid;
private Images images;
private boolean is_locked;
private boolean is_mobile;
private boolean is_parental_locked;
private String kind;
private List mobile_networks;
private String most_recent_full_episode_added_date;
private String name;
private List networks;
private List platforms;
private List ratings;
private String release_date;
private List season_filters;
private String slug;
private String tms_id;
public String get_type(){
return this._type;
}
public void set_type(String _type){
this._type = _type;
}
public List getCast(){
return this.cast;
}
public void setCast(List cast){
this.cast = cast;
}
public List getClips(){
return this.clips;
}
public void setClips(List clips){
this.clips = clips;
}
public Common_sense_data getCommon_sense_data(){
return this.common_sense_data;
}
public void setCommon_sense_data(Common_sense_data common_sense_data){
this.common_sense_data = common_sense_data;
}
public String getCommon_sense_id(){
return this.common_sense_id;
}
public void setCommon_sense_id(String common_sense_id){
this.common_sense_id = common_sense_id;
}
public List getCrew(){
return this.crew;
}
public void setCrew(List crew){
this.crew = crew;
}
public String getDescription(){
return this.description;
}
public void setDescription(String description){
this.description = description;
}
public List getEpisodes(){
return this.episodes;
}
public void setEpisodes(List episodes){
this.episodes = episodes;
}
public Number getFranchise_id(){
return this.franchise_id;
}
public void setFranchise_id(Number franchise_id){
this.franchise_id = franchise_id;
}
public List getGenres(){
return this.genres;
}
public void setGenres(List genres){
this.genres = genres;
}
public String getGuid(){
return this.guid;
}
public void setGuid(String guid){
this.guid = guid;
}
public Images getImages(){
return this.images;
}
public void setImages(Images images){
this.images = images;
}
public boolean getIs_locked(){
return this.is_locked;
}
public void setIs_locked(boolean is_locked){
this.is_locked = is_locked;
}
public boolean getIs_mobile(){
return this.is_mobile;
}
public void setIs_mobile(boolean is_mobile){
this.is_mobile = is_mobile;
}
public boolean getIs_parental_locked(){
return this.is_parental_locked;
}
public void setIs_parental_locked(boolean is_parental_locked){
this.is_parental_locked = is_parental_locked;
}
public String getKind(){
return this.kind;
}
public void setKind(String kind){
this.kind = kind;
}
public List getMobile_networks(){
return this.mobile_networks;
}
public void setMobile_networks(List mobile_networks){
this.mobile_networks = mobile_networks;
}
public String getMost_recent_full_episode_added_date(){
return this.most_recent_full_episode_added_date;
}
public void setMost_recent_full_episode_added_date(String most_recent_full_episode_added_date){
this.most_recent_full_episode_added_date = most_recent_full_episode_added_date;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public List getNetworks(){
return this.networks;
}
public void setNetworks(List networks){
this.networks = networks;
}
public List getPlatforms(){
return this.platforms;
}
public void setPlatforms(List platforms){
this.platforms = platforms;
}
public List getRatings(){
return this.ratings;
}
public void setRatings(List ratings){
this.ratings = ratings;
}
public String getRelease_date(){
return this.release_date;
}
public void setRelease_date(String release_date){
this.release_date = release_date;
}
public List getSeason_filters(){
return this.season_filters;
}
public void setSeason_filters(List season_filters){
this.season_filters = season_filters;
}
public String getSlug(){
return this.slug;
}
public void setSlug(String slug){
this.slug = slug;
}
public String getTms_id(){
return this.tms_id;
}
public void setTms_id(String tms_id){
this.tms_id = tms_id;
}
}
here is the Network Pojo class -
public class Networks{
private String banner;
private String description;
private boolean is_locked;
private String logo;
private String name;
private String network_analytics;
private Number network_id;
private String slug;
private String thumbnail_url;
private String url;
public String getBanner(){
return this.banner;
}
public void setBanner(String banner){
this.banner = banner;
}
public String getDescription(){
return this.description;
}
public void setDescription(String description){
this.description = description;
}
public boolean getIs_locked(){
return this.is_locked;
}
public void setIs_locked(boolean is_locked){
this.is_locked = is_locked;
}
public String getLogo(){
return this.logo;
}
public void setLogo(String logo){
this.logo = logo;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public String getNetwork_analytics(){
return this.network_analytics;
}
public void setNetwork_analytics(String network_analytics){
this.network_analytics = network_analytics;
}
public Number getNetwork_id(){
return this.network_id;
}
public void setNetwork_id(Number network_id){
this.network_id = network_id;
}
public String getSlug(){
return this.slug;
}
public void setSlug(String slug){
this.slug = slug;
}
public String getThumbnail_url(){
return this.thumbnail_url;
}
public void setThumbnail_url(String thumbnail_url){
this.thumbnail_url = thumbnail_url;
}
public String getUrl(){
return this.url;
}
public void setUrl(String url){
this.url = url;
}
}
and here is my code through which I am trying to extract the network names -
public class util {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
List<JsonGen> jsongenShow = null;
String url1 = "http://www.dishanywhere.com/radish/v20/dol/home/carousels/shows.json";
getShowNWGopherParser(nwork, url1);
}
public static String[] getShowNWGopherParser (List<Networks> nwork, String url ) throws JsonParseException, JsonMappingException, IOException
{
URL jsonUrl = new URL(url);
ObjectMapper objmapper = new ObjectMapper();
//objmapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
nwork = objmapper.readValue(jsonUrl, new TypeReference<List<Networks>>() {});
String [] shows = new String [nwork.size()];
int i = 0;
for(Networks element : nwork) {
shows[i++]=element.getUrl();
}
for(int j =0; j<shows.length;j++)
{
System.out.println(shows[j]);
}
return shows;
}
}
and here is the error -
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "networks" (class featureshows.Networks), not marked as ignorable (10 known properties: , "logo", "slug", "name", "banner", "network_id", "url", "network_analytics", "description", "thumbnail_url", "is_locked"])
at [Source: http://www.dishanywhere.com/radish/v20/dol/home/carousels/shows.json; line: 1, column: 15] (through reference chain: featureshows.Networks["networks"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:568)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:650)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:830)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:310)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:112)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:226)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:203)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2563)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1789)
at functions.util.getShowNWGopherParser(util.java:77)
at functions.util.main(util.java:31)
The reason is that you're using a regular List interface for your list of networks instead of the generic version with the bounds for the expected type.
Try changing the field declaration from:
private List networks;
to
private List<Networks> networks;
While you're at it, it looks like you're using the regular List interface pretty much everywhere. You'll probably run into more issues if you don't convert them all to include the type you expect in the list.
Essentially, you're not providing enough information about the type of object you expect in the list for jackson to figure out what to populate it with. You can read more about generics here: http://docs.oracle.com/javase/tutorial/extra/generics/intro.html
EDIT:
It looks (from your comment) that you've already tried disabling checks for unknown properties, but try adding this annotation to your Networks class:
#JsonIgnoreProperties(ignoreUnknown = true)
I'm being given a Json file with the form:
{
"descriptions": {
"desc1": "someString",
"desc2": {"name":"someName", "val": 7.0}
}
}
I have the POJO:
public class CustomClass {
Map<String, Object> descriptions;
public static class NameVal{
String name;
double val;
public NameVal(String name, double val){...}
}
}
I can recreate the json file with the code:
CustomClass a = new CustomClass();
a.descriptions = new HashMap<String, Object>();
a.descriptions.put("desc1", "someString");
a.descriptions.put("desc2", new CustomClass.NameVal("someName", 7.0));
new ObjectMapper().writeValue(new File("testfile"), a);
But, when I read the object back in using:
CustomClass fromFile = new ObjectMapper().readValue(new File("testfile"), CustomClass.class);
then fromFile.descriptions.get("desc2") is of type LinkedHashMap instead of type CustomClass.NameVal.
How can I get Jackson to properly parse the type of the CustomClass.NameVal descriptors (other than making some class that wraps the parsing and explicitly converts the LinkedHashMap after Jackson reads the file)?
Try this. Create a class Description with name and value attributes:
public class Description {
private String name;
private double val;
}
Now in your CustomClass do this:
public class CustomClass {
List<Description> descriptions;
}
And that's it. Remember to create getters and setters because Jackson needs it.
You could try something like this:
public class DescriptionWrapper {
private Description descriptions;
public Description getDescriptions() {
return descriptions;
}
public void setDescriptions(Description descriptions) {
this.descriptions = descriptions;
}
}
public class Description {
private String desc1;
private NameValue desc2;
public String getDesc1() {
return desc1;
}
public void setDesc1(String desc1) {
this.desc1 = desc1;
}
public NameValue getDesc2() {
return desc2;
}
public void setDesc2(NameValue desc2) {
this.desc2 = desc2;
}
}
public class NameValue {
private String name;
private double val;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getVal() {
return val;
}
public void setVal(double val) {
this.val = val;
}
}