I have a nested JSON object, for example :
{
"references": [
"CONTRACT",
"DURATION",
"EDUCATIONLEVEL",
"EXPERIENCELEVEL",
"LANGUAGELEVEL",
"CIVILITY",
"AVAILABILITY"
],
"unavailablenetworks": [
{
"content": "Service unavailable",
"id": "100"
},
{
"content": "Service unavailable",
"id": "200"
}
],
"urls": {
"apiurl": "https://xxxxxxxxxxx",
"base": "https://yyyyyyyyyyyyyy",
"video": "https://zzzzzzzzzzzzz"
}
}
and the following Java classes :
public class Version implements Serializable {
#SerializedName("references")
private List<String> references;
#SerializedName("unavailablenetworks")
private List<UnavailableNetwork> unavailableNetworks;
#SerializedName("urls")
private BKUrls urls;
}
public class BKUrls implements Serializable {
#SerializedName("apiurl")
private String api;
#SerializedName("base")
private String base;
#SerializedName("video")
private String video;
#SerializedName("edition")
private String edition;
#SerializedName("offer")
private String offer;
#SerializedName("search")
private String search;
}
public class UnavailableNetwork implements Serializable {
#SerializedName("content")
private String content;
#SerializedName("id")
private String id;
}
Getter and Setter methods are omitted here to simplify reading.
I use GSON to parse the JSON :
Gson g = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
Version version = g.fromJson(json.toString(), Version.class);
This code is using in an Android application that I'm developping.
If I install and run the application on an Android Smartphone in debug mode using Android Studio, Gson parses the Json Object correctly.
But If I try to generate an apk and then, install that apk on the same smartphone, Gson does not parse the JSON entirely. The result is like this :
{
"references": [
"CONTRACT",
"DURATION",
"EDUCATIONLEVEL",
"EXPERIENCELEVEL",
"LANGUAGELEVEL",
"CIVILITY",
"AVAILABILITY"
],
"unavailablenetworks": [
{
"id": "100"
},
{
"id": "200"
}
],
"urls": {
}
}
"references" is ok
"unavailablenetworks" is incomplete, missing "content" field
"urls" is empty
I don't understand why Gson doesn't work the same ? Why some data are missing using apk while using Android Studio in debug mode all data are ok ?
Related
I am new to Android development and learning how to use Retrofit and I am having a hard time to deal with inconsistency response from the server.
There are more than two kinds of responses will be returned from the server.
May I know how to deal with this kind of server response? Should I create different data class to handle it based on the server response?
Server Response
Result - Success
{
"status": true,
"result": {
"id": 1,
"name": "User",
"email": "user#gmail.com"
}
}
Result - Fail
{
"status": false,
"result": []
}
Android Model
public class User implements Serializable {
private boolean status;
private ResultModel result;
public static class ResultModel implements Serializable{
private String id;
private String name;
private String email;
}
}
I am trying to use realm sync, I followed the steps in the docs, I created a schema and then copied the java object models that realm suggested in the android app, but for some properties like int, double it gives an error.
The schema:
{
"title": "Invoice",
"properties": {
"_id": {
"bsonType": "objectId"
},
"ownerId": {
"bsonType": "string"
},
"customerId": {
"bsonType": "string"
},
"date": {
"bsonType": "date"
},
"invoiceItems": {
"bsonType": "array",
"items": {
"bsonType": "object",
"properties": {
"_id": {
"bsonType": "objectId"
},
"quantity": {
"bsonType": "int"
},
"trackId": {
"bsonType": "string"
},
"unitPrice": {
"bsonType": "double"
}
}
}
},
"total": {
"bsonType": "double"
}
}
}
The suggested model:
CASE 1: If I use int and double
public class Invoice extends RealmObject {
#PrimaryKey
private ObjectId _id;
private String ownerId;
private String customerId;
private Date date;
private double total;
RealmList<InvoiceItem> invoiceItems;
//getters, setters
}
The Error: Failed to transform received changeset: Schema mismatch: Property 'total' in class 'Invoice' is nullable on one side and not on the other.
CASE 2: If I use Integer and Double
public class Invoice extends RealmObject {
#PrimaryKey
private ObjectId _id;
private String ownerId;
private String customerId;
private Date date;
private Double total;
RealmList<InvoiceItem> invoiceItems;
//getters, setters
}
The error: E/AndroidRuntime: FATAL EXCEPTION: main Process: realm.example.mediastore, PID: 12939 java.lang.IllegalStateException: The following changes cannot be made in additive-only schema mode: - Property 'Invoice.total' has been made optional. at io.realm.internal.OsSharedRealm.nativeGetSharedRealm(Native Method) at io.realm.internal.OsSharedRealm.<init>(OsSharedRealm.java:175) at io.realm.internal.OsSharedRealm.getInstance(OsSharedRealm.java:251) at io.realm.BaseRealm.<init>(BaseRealm.java:141) at io.realm.BaseRealm.<init>(BaseRealm.java:108) at io.realm.Realm.<init>(Realm.java:159) at io.realm.Realm.createInstance(Realm.java:495) at io.realm.RealmCache.createInstance(RealmCache.java:494) at io.realm.RealmCache.doCreateRealmOrGetFromCache(RealmCache.java:461) at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:422) at io.realm.Realm.getInstance(Realm.java:424) ...
So neither is working. I don't how how to solve this.
Terminating sync, wiping the client and then re-enabling sync solved it.
I'm trying to parse a JSON object using retrofit 2.0 following this guide, but it doesn't work. I think it's because of a difference in JSON format.
Here is a nested JSON object with the format:
{
"SearchService": {
"list_total_count": 531,
"RESULT": {
"CODE": "INFO-001",
"MESSAGE": "SUCCESS"
},
"row": [{
"ID": "1983",
"NAME": "SAN",
"NUM": "38",
}, {
"ID": "1984",
"NAME": "DU",
"NUM": "27",
}]
}
}
Here is class code using SerializedName:
RowList.java
public class RowList {
#SerializedName("row")
#Expose
private ArrayList<Row> rows= new ArrayList<>();
public ArrayList<Row> getRows() {
return rows;
}
public void setRows(ArrayList<Row> rows) {
this.rows= rows;
}
}
Row.java
public class Row{
#SerializedName("ID")
#Expose
private String id;
#SerializedName("NAME")
#Expose
private String name;
#SerializedName("NUM")
#Expose
private String num;
/*getter setter*/
}
Read that guide.
There are two approaches to create Model class. The first way is the manual approach, which requires you to learn how to use the Gson library. The second approach is you can also auto-generate the Java classes you need by capturing the JSON output and using jsonschema2pojo
Looks like you've attempted approach one, but haven't (yet?) tried reading over the Gson documentation.
Okay, you have a Row. That covers the objects within "row": [...], so you also need objects for the following:
"SearchService": {}
"RESULT": {}
I don't think the RowList class is necessary. List<Row> is fine.
For example,
class Result {
#SerializedName("CODE")
String code;
#SerializedName("MESSAGE")
String message;
}
class SearchService {
#SerializedName("list_total_count")
long count;
#SerializedName("RESULT")
Result result;
#SerializedName("row")
private ArrayList<Row> rows= new ArrayList<>();
}
(removed #Expose for conciseness)
Then, Retrofit would use Call<SearchService>
Am trying Retrofit to get this response
POST : https://wrlyxhnjw3.execute-api.us-east-1.amazonaws.com/prod/pacakageinfo
BODY : {"type":"carwash"}
Response
[
{
"title": "SEDAN/NON SEDAN Exterior",
"choice": "Exterior Only",
"price": "$29.95/34.95 +",
"description": [
"Full body waterless car wash",
"Windows & Mirrors cleaning",
],
"addons": [
{
"price": "29.95",
"title": "Sedan 29.95$ USD"
},
{
"price": "34.95",
"title": "Non-Sedan SUV 34.95$ USD"
}
]
},
{
"title": "SEDAN/NON SEDAN",
"choice": "Exterior & Interior",
"price": "$34.95/44.95 +",
"description": [
"Full body waterless car wash",
"Leather cleaning & Care"
],
"addons": [
{
"price": "34.95",
"title": "Sedan 34.95$ USD"
},
{
"price": "44.95",
"title": "Non-Sedan/SUV 44.95$ USD"
}
]
}
]
PackagesAPI Class
public interface PackagesAPI {
#POST("/prod/pacakageinfo")
Call<List<PackagesAdapter.Item>> loadPackages(#Body PackagesFragment.PackageType packageType);
}
GetPackagecall (In a Package Fragment)
private void getPackagesCall(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://wrlyxhnjw3.execute-api.us-east-1.amazonaws.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
PackagesAPI packagesAPI = retrofit.create(PackagesAPI.class);
Call<List<PackagesAdapter.Item>> call = packagesAPI.loadPackages(new PackageType("carwash"));
call.enqueue(this);
}
public class PackageType {
final String type;
PackageType(String type) {
this.type = type;
}
}
Public Objects in class PackageAdapter
public class Item {
String title;
String choice;
String price;
public List<String> description = new ArrayList<String>();
public List<Addon> addons = new ArrayList<Addon>();
}
public class Addon {
String price;
String title;
}
But it gives "Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path" exception?
I saw other posts like this and generally there's an issue with object definitions?
Am not able to figure out what's wrong here, I tried jsonschema2pojo.
You should try and make Item and Addon classes to be static or move them into their own class definitions (out of PackageAdapter). So in this solution, I am assuming that you move these classes to their separate class files/definitions if there are no compelling reasons for having them as inner classes.
In Item.java:
public class Item {
String title;
String choice;
String price;
public List<String> description = new ArrayList<String>();
public List<Addon> addons = new ArrayList<Addon>();
}
In Addon.java
public class Addon {
String price;
String title;
}
Instead of making the member variables to be public, please try moving either making these inner classes to be static, or move them to separate class files (recommended). Test it out and let us know if it solves the problem.
So I'm working with retrofit with an API that has a variable called "public". How would I go about getting it to automatically map like all the other variables do.
Example:
#GET("/?filter=my_images")
void getMyImages(
#Query("client_id") String id,
#Query("api_key") String key,
Callback<ImageList> callback
);
public static class Image{
int id;
String name;
String distribution;
String slug;
// Can't do this:
boolean public;
}
public static class ImageList{
String status;
List<Image> images;
}
Example API results (json):
{
"status": "OK",
"images": [
{
"id": 1,
"name": "My first snapshot",
"distribution": "Ubuntu",
"slug": "ubuntu-12.10-x32",
"public": true
},
{
"id": 2,
"name": "Automated Backup",
"distribution": "Ubuntu"
}
]
}
Retrofit uses Gson for serialization to and from JSON.
Gson provides a #SerializedName annotation in order to change the key to which a field or method is mapped. You can use this for handling your reserved word:
#SerializedName("public")
public String isPublic;
Please look at this link, which is a neater solution if there are underscores in each key.