Json to pojo unmarshaler with polymorph classes for android - android

I am having a problem with rest and android,
the problem is I have a transport object in example a class Human, which is extended by Male and Female, I want to use json as transport for the human object.
if I use standard serialized objects, i would usually do
if(human instanceof Male.class){}
else if(human instance of Female.class){}
else{ throw new RuntimeException("incorrect class")}
how do I implement this in android with rest?
I've seen that Gson and Jaskson which do not support polymorphism,
on the server side we're using Apache CXF for rest, with jax-rs annotations
Ideas/previous experiences??

I don't know of any automatic way to perform de-serialization, but one solution is to use a "duck typing" parser for your JSON.
Assume the following
class Human {
public Human(JSONObject jo) {
// Parse out common json elements
}
}
class Male {
private boolean hasMaleParts;
public Male(JSONObject jo) {
super(jo);
// Parse out male only parts
}
}
class Female {
private boolean hasFemaleParts;
public Female(JSONObject jo) {
super(jo);
// Parse out female only parts
}
}
With these three classes, somewhere in your network access code, have a method which types your returned JSON and returns the appropriate object.
public Human typeJson(JSONObject jo) {
if(jo.hasBoolean(hasMaleParts))
return new Male(jo);
else if(jo.hasBoolean(hasFemaleParts))
return new Female(jo);
else
throw new RuntimeException("Unable to determine data type");
}
In this example hasMaleParts and hasFemaleParts are arbitrary boolean flags, however, in many instances you could (more properly) type it using identifying attributes. So, if you were trying to distinguish between Motorcycle and Car, you might check number_of_wheels.

Related

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.

How to get two objects - raw Response object and POJO - all at once with Retrofit?

I'm using Retrofit/OkHttp in a project and recently I've discovered RxJava. Combining it with Retrofit seems easy and straightforward but with regular async callbacks in Retrofit in success(...) we are receiving the parsed POJO and the Response. This is quite useful and in some of my callbacks I'm using both of these objects. I can't seem to find a way to do this with RxJava.
Is it possible to obtain the parsed POJO and the Response object at the same time?
The way RxJava works is that the onNext method always emits exactly one value, so you won't be able to get something like (as it would break the contract):
onNext(T value, Response respone);
The closest could be an Observable<ResponseAndPojo<T>> where ResponseAndPojo is as follows:
public class ResponseAndPojo<T> {
private final T value;
private final Response response;
public ResponseAndPojo(T value, Response response) {
this.value = value;
this.response = response;
}
// add getters here
}
Such an Observable would then emit items with:
onNext(ResponseAndPojo<T> responseAndPojo)
and you would have access to both the Response and the POJO.
Now, how to construct such an Observable:
One way would be to create some kind of Subject (maybe a BehaviorSubject, but for single requests it does not really matter) and then in the Retrofit success method put the return values into the Subject.
So, in some kind of RetrofitWrapper class of your own you would have
public Observable<ResponseAndPojo<YourPojoClass>> getResponseAndPojoObservable() {
final BehaviorSubject<ResponseAndPojo<YourPojoClass>> retrofitSubject = BehaviorSubject.<ResponesAndPojo<YourPojoClass>>create();
yourRetrofitService.getSomething(new Callback<YourPojoClass>() {
#Override
public void success(YourPojoClass pojo, Response response) {
retrofitSubject.onNext(new ResponseAndPojo(pojo, response);
retrofitSubject.onCompleted();
}
});
return retrofitSubject;
}
As you can see, from the outside the Subject looks like an Observable<ResponseAndPojo<YourPojoClass>>, which is exactly what we wanted.

Custom error handling with Retrofit

The REST Api I'm working with has custom codes and messages which are sent from server depending on the state, I would like to implement a custom Callback<T> that calls the success method only if the status code was 0.
Example SUCCESS Response received from server:
{
"code":"0",
"message":"success",
"data": {
"actual_data":"goes_here",
"need_to_construct_objects","from_data"
}
}
Example of FAILURE Response:
{
"code":"301",
"message":"wrong_password",
"data": {
"actual_data":"will_be_null",
"no_need_to_construct_objects","from_data"
}
}
code and message are returned by all requests, the data contains the actual response values, so I would like to do the following:
Check the code and message and only call success() if code is 0.
Call failure() if request failed or code != 0
Construct custom objects based on the data response and pass them via success()
What is the best way to do this? I searched everywhere and could not find a good solution. The only one I got was to let all custom objects have the code and message fields too and check their values inside success(), but this could cause problems in future in case someone forgets to check the code before proceeding.
You can do that quickly by just making an abstract class that implements Callback, and declare your own abstract success and failure methods. The abstract class will handle Retrofit's standard callback methods, interpret the response and call the abstract methods accordingly.
I think another possible approach to this is to override Retrofit's Client interface to build your own Response object.
If you extend OkClient, it can go like this:
public class CustomClient extends OkClient {
#Override public Response execute(Request request) throws IOException {
Response originalRespone = super.execute(request);
int statusCode = 0;
//TODO: read JSON response here (using GSON or similar, and extract status code and message... etc.)
//Convert the status code to HTTP standard status codes, according to the documentation you have.
if(statusCode == 0) statusCode = 200;
//Reconstruct a Response object
return new Response(originalResponse.getUrl(), statusCode, originalResponse.getReason() /*should probably replace with parsed message*/, originalResponse.getHeaders(), originalResponse.getBody());
}
This may be more work than handling your case in Callback, but I think it can help if at some point the API transitions to RESTful API conventions.
This solution comes with its own problem though, because that means the JSON conversion will run twice. One in your client, and another one by Retrofit. Not sure the correct way to do that at the moment. Probably something around TypedInput and a dummy Converter that passes already converted objects.
Create a custom ResponseBodyConverter like this:
public class CustomResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final TypeAdapter<T> adapter;
CustomResponseBodyConverter(TypeAdapter<T> adapter) {
this.adapter = adapter;
}
#Override
public T convert(ResponseBody value) throws IOException,CustomException {
String json = "";
try {
String body = value.string();
json = new JSONObject(body).getJSONObject("data").toString();
int code = new JSONObject(body).getInt("code");
String message = new JSONObject(body).getString("message");
if(code != 0){
throw new CustomException(message);
}
} catch (JSONException e) {
e.printStackTrace();
}
return adapter.fromJson(json);
}
}
It's a better idea to implement a custom callback. You can an example about it below.
public abstract class DefaultRequestCallback<T> implements Callback<T> {
public abstract void failure(Meta meta);
public abstract void success(T responseBean);
#Override
public void success(T baseResponseBean, Response response) {
// You can check your responsebean's error code and
// convert it to a default error
BaseResponseBean bean = (BaseResponseBean) baseResponseBean;
if (bean == null) {
failure(new Meta(ApplicationConstants.ERROR_RETROFIT, "Unknown Error!"));
} else if (bean.getMeta() != null && bean.getMeta().getCode() != ApplicationConstants.RESULT_SUCCESS) {
failure(bean.getMeta());
} else {
success(baseResponseBean);
}
}
#Override
public void failure(RetrofitError error) {
// Convert default error to your custom error.
Meta meta = new Meta(ApplicationConstants.ERROR_RETROFIT, "Error Unknwon");
failure(meta);
}
}
Give your custom callback to your retrofit service interface method.
void yourMethod(DefaultRequestCallback<YourResponseBean> callback);
Good Luck.
This will at least get you started. You can basically create your own custom callback and then handle the success. Look at what was sent and do what you need to.
public class CustomCallback implements Callback {
#Override
public void success(Object o, Response response) {
//Check for success
//if( Success )
//callback.success(o, response);
//else
//Check for error
//callback.failure(error);
}
}
In your case, you can have a class that maps your json response:
class CustomResponse {
String code;
String message;
Data data;
static class Data {
String actualData;
String needToContructObjects;
String noNeedToContructObjects;
}
}
Then, since you're back to the java objects world, you can have a factory-like object inside your success method callback that creates the desired object based on the returned custom response. If you want to get this response in the failure callback, I'd reconsider using Retrofit, since your API is not following a good Rest design.
Although this is plenty possible, and understanding you might not be involved on the API development, be aware this is not a good API design approach. If you are POSTing a login request to the server, you can understand this request as a request to create a resource (an authenticated user session, for instance). If you don't send the correct parameters (the correct username and password in this specific case), the server should reject the resource creation request and send back a 4-hundred-something (4xx) http status code indicating your request was not correct somehow. Retrofit would understand this 4xx status code and call your failure callback, where you could handle the response appropriately.

JSONObject as class attribute storage/retrieval

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.

How to parse a regular String to an XML file

What I'm trying to do is to parse an object into a String, and then , parse it into an XML so any other language can translate it.
Figure out this object:
public class DatosPac
{
private String nombre;
private String apellidos;
private String dni;
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getApellidos() {
return apellidos;
}
public void setApellidos(String apellidos) {
this.apellidos = apellidos;
}
public String getDni() {
return dni;
}
public void setDni(String dni) {
this.dni = dni;
}
}
What I want to do is, parse it into a common XML between Android and .Net so both languages can translate the same object. The way to communicate both languages will be using Web Services, so the Web Service will receive a String, transalte it into the object and then use the information. Bidirectionally. I mean, Android will be able to receive an object parsed from .Net, and .Net will be able to receive the same object from Android. To be able to do this, I think I need to convert them into the same XML, but I don't know how to do it in Android.
Thanks in advance.
There are several XML serializing and de-serializing libraries available for Android. And I am sure the same's the case with .NET.
You set up your objects as POJOs and with a few annotations, you can serialize/deserialize in a few lines of code. In the Android world, I personally prefer Simple, but there are various other libraries available.
A more compact, (and more efficient, in terms of parsing) data representation format is JSON. There are multiple libraries available for parsing and constructing JSON too. My preferred one for Android is Gson.
EDIT: I believe I was a bit too quick! I didn't notice the android tag and assumed a .net context. Still, one bit stands: You probably want to serialize, not to "parse" the object, into XML.

Categories

Resources