JSONObject as class attribute storage/retrieval - android

In android, I'm using model classes with methods to handle the data manipulation. My data is brought in from webservices as json. I'm contemplating the possibility of using JSONObjects to store the values of class level attributes. But, I don't know of a way to use the JSONObj as the "holder" variable and create access methods. I don't want to predetermine these methods, as jsonRepository should hold the values, not always known at design time
For example, I'd like to have:
public class User {
private JSONObject jsonAttributes;
public User(String json) {
this.jsonAttributes= new JSONObject(json);
}
[IMPLICIT attribute access methods]
public string Prop1() returns jsonAttributes.getString("prop1");
public string Prop1(String newProp1) returns jsonAttributes.putString("prop1",newProp1);
public string Prop2() returns jsonRepository.getString("id");
public string Prop2(String newProp2) returns jsonAttributes.putString("prop2",newProp2);
....
from outside this class then, I would access the attributes simply...
User myUser = new User(someValidJson);
String myString = myUser.Prop1
Misguided? If not, how does one manage implicit property setting/getting?

As was mentioned in the comment above, why not create your user class, with all of the relevant memeber variables, and simply parse your JSON data in order to populate the ionformation in your user class.
There are a lot of ways you can do this, but I would consider using the builder pattern, as it is flexible, which could be useful if your JSON data changes in the future.

Related

GSON : Custom serialization for String

public class Data{
public String str; //String (that may contain line breaks) I need to serialize as it is.
}
Why I needed custom Serializer for string?
Without custom serializer it serializes this as object {"str":{"count": 292,"hashCode": 0} }
I need it to be {"str":"..............."}
How to do it with custom Serializer?
There are example of custom serializer for custom types, but could not find anything that helps to serialize String type.
Well, Gson supports strings out of box and you don't have to implement any string serializer and vice versa yourself. What I guess might happen to your case is merely importing a wrong string class, say import foo.bar.baz.String; or less obvious import foo.bar.baz.*, or you just have a String class implementation right in the package where your Data class is declared in. (This cannot explain what values were really assigned to str, though, -- it would never work in Java causing ClassCastException). A wrong class might be indicated with numeric count and hashCode without any char[]-declared fields, so I don't believe this is a java.lang.String in your case. Also, a more hypothetical thing here might be use of reflection that discarded the string type adapter out of your Gson instance, no matter how and how weird it sounds. In any case, you don't have to implement even a single line to serialize Java strings with Gson.
Regarding the accepted answer: it is suboptimal. If, for whatever reason, there is nothing wrong with your imports, your package does not declare a custom String class, and your Gson instances do not suffer from reflection surgery, but Gson still serializes such strings as nested objects (have no ideas why then), you'd only need a single special String type adapter without any need of creating type adapters for any class that uses that weird String as a field:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(/*real.package.here.*/String.class, (JsonSerializer</*real.package.here.*/String>) (s, type, context) -> new JsonPrimitive(s.toString())) // whatever the real Java string is obtained
.create();
Try this
public class DataSerializer implements JsonSerializer<Data> {
#Override
public JsonElement serialize(Data data, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.addProperty("src", data.src);
return object;
}
}
Add this to Gson Like this
Gson gson = new GsonBuilder()
.registerTypeAdapter(Data.class, new DataSerializer())
.create();

Best practices for fetching same data in multiple objects using web service VS front-end computations for accessing existing data?

In my application I have fetched some data called data1 from web server and displayed, after two three screen navigation I need some data which is existing in data1 but it requires some iterations to access, So is this right I should invoke another web service which is providing required data or front end computations needs to be done.
YOu can Save your data in a Separate class and fetch from there when you need it,
like getter setter.
Like this..
public class Global {
private static JSONObject jsonObject;
public static void saveData(JSONObject object) {
jsonObject = object;
}
public static JSONObject getData() {
return jsonObject;
}
}
From your Activity:
Global.saveData(jsonObject);
Orr
JsonObject jsonObj = Global.getData();

Practical use of #Ignore in Realm?

I've been trying to add Realm in my Android app. Their docs are pretty well explained & easy to follow. But it fails to explain this one particular area. I'm unable to figure out the practical use for the #Ignore annotation. I know that fields under this annotation are not persisted.
Can someone please share a few use cases. Also I wanted to know the scope of such fields. I mean, if I set an #Ignore field to some value, would that value be available to the other classes in my app for that particular launch session. If yes, then how do we access it? If no (which I guess is the case), then why do we need such a field anyway?
I've searched here and on web but couldn't find the relevant information. If out of my ignorance, I've missed upon some resource, please guide me to it.
Thanks.
Accordingly to the official documentation (see https://realm.io/docs/java/latest/) #Ignore is useful in two cases:
When you use GSON integration and your JSON contains more data than you want to store, but you still would like to parse it, and use right after.
You can't create custom getters and setter in classes extending RealmObject, since they are going to be overridden. But in case you want to have some custom logic anyway, ignored fields can be used as a hack to do that, because Realm doesn't override their getter & setters. Example:
package io.realm.entities;
import io.realm.RealmObject;
import io.realm.annotations.Ignore;
public class StringOnly extends RealmObject {
private String name;
#Ignore
private String kingName;
// custom setter
public void setKingName(String kingName) { setName("King " + kingName); }
// custom getter
public String getKingName() { return getName(); }
// setter and getter for 'name'
}
Ignored fields are accessible only from the object they were set in (same as with regular objects in Java).
UPDATE: As the #The-null-Pointer- pointed out in the comments the second point is out of date. Realm now allows having custom getters and setters in Realm models.
Here's a couple of real-world use cases:
1 - Get user's fullname:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private String fullName;
public String getFullName() {
return getFirst() + " " + getLast();
}
Get JSON representation of object:
public class User extends RealmObject {
private String first;
private String last;
#Ignore
private JSONObject Json;
public JSONObject getJson() {
try {
JSONObject dict = new JSONObject();
dict.put("first", getFirst());
dict.put("last", getLast());
return dict;
} catch (JSONException e) {
// log the exception
}
return null;
}
I've found it useful to define field names for when I am querying. For example
User.java
public class User extends RealmObject {
#Index
public String name;
#Ignore
public static final String NAME = "name";
}
And then later on I can do something like:
realm.where(User.class).equalTo(User.NAME, "John").findFirst();
This way if the schema changes from say name to id I don't have to hunt down every occurrence of "name".
Please see the the official documentation about #Ignore annotation:
The annotation #Ignore implies that a field should not be persisted to disk. Ignored fields are useful if your input contains more fields than your model, and you don’t wish to have many special cases for handling these unused data fields.

How #JsonProperty working using jackson parser in android

In this below code, if I access getBl_no () its correctly returning value. I don't know how it's working I didn't set bl_no anywhere is that Json property will set to that set method? Please anyone explain.
#JsonProperty("BL_NO")
private String bl_no;
public String getBl_no() {
return bl_no;
}
public void setBl_no(String bl_no) {
this.bl_no = bl_no;
}
#JsonProperty annotation is where the magic happens! The JSON parser that you use reads the JSON property named BL_NO and assigns its value to the private instance variable bl_no. You don't even need a setBl_no() method for this to work.
#JsonProperty annotation lets you tell the JSON parser that while serializing or deserializing, the JSON property BL_NO should be tied to variable bl_no. That's how the variable gets initialized with a value even though you don't explicitly do it.

Reducing number of event classes when using EventBus or Otto

I am about to start development on an Android app. I am interested in using Otto or EventBus in my app to assist with making asynchronous REST network calls and notifying the main thread when the calls have returned.The one major flaw with the use of these busses that I have found during research is that there are typically too many event classes that have to be created. Are there any patterns or approaches to reduce the number of event classes that have to be used?
The concept
The best way i have solved the issue of too many event classes is by using Static Nested Classes You can read up more about them here.
Now using the above concept here is how you would solve the problem:
So basically suppose you have a class called Doctor that you are using to create an object you are passing around with your application. However you want to send the same Object over the network and retrieve JSON in the context of that same object and feed it back to a subscriber to do something with. You would probably create 2 classes
DoctorJsonObject.java that contains information about the returned JSON data and
DoctorObject.java that has data you are passing around in your app.
You don't need to do that.
Instead do this:
public class Doctor{
static class JSONData{
String name;
String ward;
String id;
//Add your getters and setter
}
static class AppData{
public AppData(String username, String password){
//do something within your constructor
}
String username;
String password;
//Add your getters and setters
}
}
Now you have one Doctors Class that Encapsulates both the events for the post to the network and the post back from the network.
Doctor.JSONData represents data returned from the network in Json format.
Doctor.AppData represents "model" data being passed around in the app.
To use the class' AppData object then for the post event:
/*
You would post data from a fragment to fetch data from your server.
The data being posted within your app lets say is packaged as a doctor
object with a doctors username and password.
*/
public function postRequest(){
bus.post(new Doctor.AppData("doctors_username","doctros_password"));
}
The subscriber within you implementation that listens for this object and makes an http request and returns the Doctor.JSONData:
/*
retrofit implementation containing
the listener for that doctor's post
*/
#Subscribe
public void doctorsLogin(Doctor.AppData doc){
//put the Doctor.JSONObject in the callback
api.getDoctor(doc.getDoctorsName(), doc.getPassWord(), new Callback<Doctor.JSONObject>() {
#Override
public void success(Doctor.JSONObject doc, Response response) {
bus.post(doc);
}
#Override
public void failure(RetrofitError e) {
//handle error
}
});
}
}
With the above implementation you have encapsulated all Doctor Object related events within ONE Doctor class and accessed the different types of objects you need at different times using static inner classes. Less classes more structure.

Categories

Resources