How to handle such a json properly? - android

The problem is next.
In response I have JSON like
{
object: {
// a lot of different fields
}
}
I use Retrofit with gson parser. What I really need is just this object. I don't want to create class for response with the only one field. All responses server send in a such manner. As far I understand somewhere I need place simple code for fetching that one object and then use default parser for it.
Probably sorry for stupid question. I used Volley and there was quite a different approach.

Instead of creating a special class to handle this (and another special class for every other server response), just use Map<String, YourRealObjectType>. Then use this method to extract the YourRealObjectType instance for each response:
public static <T> T getFirstValue(Map<String, T> map) {
return map.values().iterator().next();
}

you can convert class into JsonObject class. then cal iterate all the elements in it one by one
#Get
ObservablegetData();
Note : use JsonObject not JSONObject

Related

Parsing API results on Android with Retrofit and Jackson or Gson

I am trying to parse the results of an API call which returns a unique first property.
{
"AlwaysDifferent12345": {
"fixedname1" : "ABC1",
"fixedname2" : "ABC2"
}
}
I am using retrofit2 and jackson/gson and cannot figure out how to cope with dynamic property names within the retrofit2 framework. The following works fine
data class AlwaysDifferentDTO(
#JsonProperty("AlwaysDifferent12345") val alwaysDifferentEntry: AlwaysDifferentEntry
)
I have tried
data class AlwaysDifferentDTO(
#JsonProperty
val response: Map<String, AlwaysDifferentEntry>
)
But this returns errors Can not instantiate value of type... The return value from the API is fixed i.e. map<string, object>.
I have read you can write a deserializer but it looks like I need to deserialize the whole object when all I want to do is just ignore the string associated with the response.
I have read
https://discuss.kotlinlang.org/t/set-dynamic-serializedname-annotation-for-gson-data-class/14758
and several other answers. Given unique properties names are quite common it would be nice to understand how people deal with this when using retrofit2
Thanks
Because the JSON doesn't have a 1-to-1 mapping Jackson can't map it automatically using annotations. You are going to need to make your own Deserializer.
In this tutorial you can learn how to create your own custom Deserializer for Jackson. https://www.baeldung.com/jackson-deserialization
In the tutorial you will see the first line under the deserialize function is
JsonNode node = jp.getCodec().readTree(jp);
using this line you can get the JSON node as a whole and once you have it you can call this function
JsonNode AlwaysDifferent12345Node = node.findParent("fixedname1");
Now that you have that node you can retrieve its value like shown in the rest of the tutorial. Once you have all the values you can return a new instance of the AlwaysDifferentDTO data class.

Retrofit to parse json with an indefinite number of object names

I'm using retrofit to handle rest-api calls.
I have a rest API that returns the following json
"MyObject": {
"43508": {
"field1": 4339,
"field2": "val",
"field3": 15,
"field4": 586.78
},
"1010030": {
"field1": 1339,
"field2": "val212",
"field3": 1,
"field4": 86.78
},...
}
Please notice that the object MyObject contains objects with a name that is actually an id.
For all the other rest APIs I'm using retrofit without problems.
In this case it seems not possible to use the standard approach: defining a class containing the fields expected in the response.
Is there a way to transform this json into a json containing an array of
{
"field1": xxx,
"field2": "yyy",
"field3": www,
"field4": zzz
}
Or is there a better way to deal with this problem without going back to "manually" parsing the json?
Try to use next approach:
public class Response {
Map<String, YourObject> MyObject;
// getter, setter
}
public interface GitHubService {
#GET("some_path")
Call<Response> listMyObjects();
}
All you objects will be parsed to Map. You can get the list of all ids via keySet() method or list all entries with entrySet().
Try putting the annotation, SerializedName(nameOfField) over the variable name.
#SerializedName("13445345")
MyObject object;
Well my idea is quite manual, but it should work. I will not copy and paste another person's answer here, so take a look at this answer to see how to loop through all of the myObject's keys. Then for each of those keys, make a new JSONArray and add key value pair of fieldX-valueX.
This is just a basic idea, since I think you can handle the code yourself, you seem like a guy who knows his way around the simple stuff.

Is there any way to directly handle json in android/java without convert [duplicate]

I was wondering if somewhere out there exists a java library able to query a JSONObject. In more depth I'm looking for something like:
String json = "{ data: { data2 : { value : 'hello'}}}";
...
// Somehow we managed to convert json to jsonObject
...
String result = jsonObject.getAsString("data.data2.value");
System.out.println(result);
I expect to get "hello" as output.
So far, the fastest way I have found is using Gson:
jsonObject.getAsJsonObject("data").getAsJsonObject().get("data2").getAsJsonObject("value").getAsString();
It's not actually easy to write and read. Is there something faster?
I've just unexpectedly found very interesting project: JSON Path
JsonPath is to JSON what XPATH is to XML, a simple way to extract parts of a given document.
With this library you can do what you are requesting even easier, then my previous suggestion:
String hello = JsonPath.read(json, "$.data.data2.value");
System.out.println(hello); //prints hello
Hope this might be helpful either.
While not exactly the same, Jackson has Tree Model representation similar to Gson:
JsonNode root = objectMapper.readTree(jsonInput);
return root.get("data").get("data2").get("value").asText();
so you need to traverse it step by step.
EDIT (August 2015)
There actually is now (since Jackson 2.3) support for JSON Pointer expressions with Jackson. So you could alternatively use:
return root.at("/data/data2/value").asText();
First of all, I would recommend consider JSON object binding.
But in case if you get arbitrary JSON objects and you would like process them in the way you described, I would suggest combine Jackson JSON processor along with Apache's Commons Beanutils.
The idea is the following: Jackson by default process all JSON's as java.util.Map instances, meanwhile Commons Beanutils simplifies property access for objects, including arrays and Map supports.
So you may use it something like this:
//actually it is a Map instance with maps-fields within
Object jsonObj = objectMapper.readValue(json, Object.class);
Object hello = PropertyUtils.getProperty(jsonObj, "data.data2.value")
System.out.println(hello); //prints hello
You can use org.json
String json = "{ data: { data2 : { value : 'hello'}}}";
org.json.JSONObject obj = new org.json.JSONObject(json);
System.out.println(obj.query("/data/data2/value"));
I think no way.
Consider a java class
class Student {
Subject subject = new Subject();
}
class Subject {
String name;
}
Here if we want to access subject name then
Student stud = new Student();
stud.subject.name;
We cant access name directly, if so then we will not get correct subject name. Like here:
jsonObject.getAsJsonObject("data")
.getAsJsonObject()
.get("data2")
.getAsJsonObject("value")
.getAsString();
If you want to use same like java object then use
ClassName classObject = new Gson().fromJson(JsonString, ClassName.class);
ClassName must have all fields to match jsonstring. If you have a jsonobject inside a jsonobject then you have to create separate class like I'm doing in Student and Subject class.
Using Java JSON API 1.1.x (javax.json) one can make use of new JavaPointer interface. Instance implementing this interface can be considered to some extend as kind of XPath expression analog (see RFC-6901 for details). So in your case you could write this:
import javax.json.*;
//...
var jp = Json.createPointer("/data/data2/value");
System.out.println(jp.getValue(jsonObject));
In 1.1.4 version of JSON there's also nice addition to JsonStructure interface (which is implemented by JsonObject and JsonArray), namely getValue(String jsonPointer). So it all comes down to this simple one-liner:
System.out.println(jsonObject.getValue("/data/data2/value"));

Android: Is it the right approach to convert JSON to POJO?

I'm using Volley Library to get JSON responses on my requests. I created base http Helper classes which process requests and return JSON for next processing.
I would like to ask what is the right approach to process returned JSON data?
I would like to use data for displaying in ListView, View, etc. but I don't know what is the right approach (Convert to POJO or keep data in JSON?)
I tried to find any solution on this topic:
Json to POJO mapping in Android
But it seems that each object should have a single class with definition of the all possible fields of the object.
This approach seems strange to me because I have already created models for the database objects and if JSON object is changed (for example added new attribute or changed his name) it means that code on the API models should be changed too.
Is there any other possibility and the right way how to avoid this and work with returned data only in Activities (Controllers)?
Use GSON it is quite snappy and easy to use. for e.g.
Gson gson = new Gson(); // Or use new GsonBuilder().create();
MyType target = new MyType();
String json = gson.toJson(target); // serializes target to Json
MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
Read my answer completely, i've explained in easy way.
First of all if you are using Volley no need of http helper class, use Volley's method to get JSON data by objects or array.
Second POJO classes are best use it. yes it is the right approach.
Here is the source code to get json object data from volley and store in POJO.
/**
* Method to make json object request where json response starts wtih {
* */
private void makeJsonObjectRequest() {
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
"http://api.example.com", null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
try {
// Parsing json object response
// response will be a json object
String name = response.getString("name");
String email = response.getString("email");
//POJO class to store
Person person = new Person();
person.name=name;
person.email=email;
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
hidepDialog();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_SHORT).show();
// hide the progress dialog
hidepDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq);
}
I would definitely suggest you transform JSON to POJOs and use this. It is much more natural to use objects to represent data in an object oriented language, such as Java.
I would like to ask what is the right approach to processing returned JSON data?
There are two main options:
Use the built - in JSON SDK - it is a very decent tool and is adequate if you don't have complex response structures. It can be quite performant.
Use some kind of a third party JSON processing library - GSON or Jackson. They come stacked with functionality, like automatic deserialisation from JSON to POJO based on annotations, etc. This can save you time, but it is expensive. To get the best performance out of this, you should still parse the things manually, but you can start doing this only if you need to optimise.
No matter what you use, just make sure that JSON processing is done on a worker thread. If you are using Volley, you should consider extending a Request class and overriding parseNetworkResponse() - this is a good place to plug in your deserialisation. The responses will now be POJOs and you can use them to populate lists, etc.
As far as this goes:
This approach seems to me strange because i have already created models for the database objects and if JSON object is changed (for example added new attribute or changed his name) it means that code on the API models should be changed too.
Unfortunately, you are right. But this is a common problem in client - server communication. When using JSON over HTTP there is no way to enforce that the contract between server and client is being followed. The best you could do, IMHO, is detect the possible exceptions and handle them accordingly - showing a message to the user, or something like that. You can always use Maps to hold the deserialised payload as key - value pairs, but this doesn't really solve the issue, but ensures the deserialisation logic wont' fail.

GSON Dynamic Class Binding

I'm currently using GSON to parse my JSON to Objects. I was using the standard way like :
Result response= gson.fromJson(reader, Result.class);
Result can be a very complex object with other Complex objects, with up to 5 levels of complex objects. But I have no issues with that.
My Question is : I would like to be able to have in some objects an attribute with a flexible type.
For example :
class Class1 {
String hello;
}
class Class2 {
String world;
}
class Class3 {
Class<?> (= class1 or class2) hello;
}
// Parsing time
Class<?> response= gson.fromJson(reader, Class3.class);
try {
Class1 ret = (Class1)response;
} catch ... {
Class2 ret = (Class2)response;
}
Hope it's clear enough.
Unfortunately, the latest release of Gson (2.0) still doesn't have built-in support for an easy configuration to provide polymorphic deserialization. So, if Gson must be used (instead of an API that has such built-in support, like Jackson -- using which I've posted complete examples for polymorphic deserialization at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html), then custom deserialization processing is necessary.
For deserialization to polymorphic types, something in the JSON must be present to identify which concrete type to deserialize to.
One approach would be to have an element in the JSON dedicated to just this purpose, where the deserialization code selects the correct type based on the value of the special-purpose element. For example:
{"type":"Class1","hello":"Hi!"} --> deserializes to Class1 instance
{"type":"Class2","world":"Earth"} --> deserializes to Class2 instance
Another approach would be to just switch on the presence of particular JSON element names, though instead of try-catch blocks as demonstrated in the original question, I'd just use if-statements.
See Gson issue 231 for more on this topic, as well as possible information on when a built-in polymorphic deserialization facility might be included in Gson.
Another StackOverflow.com post with an example of polymorphic deserialization with Gson is Polymorphism with gson

Categories

Resources