Deserializing an object that contains a single list with gson - android

I have the following json I want to deserialize:
{
"locations": [{
"id": 17,
"account_id": 11,
"name": "The Haunted Lexington",
"radius": 100
}]
}
(In this particular instance, there's only one Location, but there can be many).
I deserialize this using Gson with the following code:
Gson gson = new GsonBuilder().create();
LocationList ll = gson.fromJson(jsonString, LocationList.class);
I have the following classes defined:
public class Location {
#SerializedName("id")
private long mId;
#SerializedName("account_id")
private long mAccountId;
#SerializedName("name")
private String mName;
#SerializedName("radius")
private int mRadius;
public long getId() {
return mId;
}
public String getName() {
return mName;
}
}
and:
public class LocationList {
#SerializedName("locations")
private List<Location> mLocations;
}
The thing is, I have a bunch of these "dummy" classes that contain a single object that's a list of other objects (e.g. UserList, MessageList, etc...)
What I'd like to do is have the above json parsed somehow so I can skip defining the intermediate class definition of LocationList, like so:
Gson gson = new GsonBuilder().create();
// Use the same json as above, but skip defining the superfluous "LocationList" class
List<Location> ll = gson.fromJson(jsonString, "locations", ArrayList<Location>.class);
Is there a way I can do this, perhaps by providing a custom deserializer?

I faced a similar problem not long ago, and solved it like this
// Parse the JSON response.
JSONArray jsonArray = new JSONArray(response);
List<Location> locations = new ArrayList<Location>();
/*
* Create a Location object for every JSONObject in the response,
* and add it to the list.
*/
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
Location location = new Gson().fromJson(jsonObject.toString(),
Location.class);
locations.add(location);
The approach here is to loop over every Location in the locations array in the JSON, extracting them one by one and then adding them to a list.
The JSON I worked with had a list as root object, so you probably can't use this JSONArray jsonArray = new JSONArray(response);. Something like this might better suit your situation
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray locationsJsonArray = jsonObject.get("locations");
I have not tested these last 2 lines, but I think you get the idea.
I hope you can use this to solve your problem.

I'm currently using a simple method to achive your goal:
private static <T> List<T> getList(final String jsonVal, final String listTag, T t) {
try {
JsonObject jsonObject = (JsonObject)(new JsonParser()).parse(jsonVal); // root JsonObject. i.e. "locations"
JsonArray jsonArray = (JsonArray)jsonObject.get(listTag);
Gson gson = new GsonBuilder().create();
List<T> list = gson.fromJson(jsonArray, new TypeToken<List<T>>() {}.getType());
return list;
} catch (Exception e) {
throw new IllegalArgumentException("Unexpected json structure!", e);
}
}
Example usage:
final GsonBuilder gsonBuilder = new GsonBuilder();
final Gson gson = gsonBuilder.create();
String jsonString = "{\"locations\":[{\"id\":17,\"account_id\":11,\"name\":\"The Haunted Lexington\",\"radius\":100}]}";
List<Location> list = getList(jsonString, "locations", new Location());
This method should be used for your orther classes, such as:
List<User> userList = getList(jsonString, "users", new User());
List<Message> messageList = getList(jsonString, "messages", new Message());

Related

Array as parameter in retrofit

I have an issue with my parameters passing in retrofit, My problem is need to send int array ([3,1,2]) as one of the parameters in a POST method with retrofit 2, other parameters are as string. (ex: tips - "10", amount-"100", service-ids -[3,1,2]). How can send parameters like above in example.
You can use ArrayList such as:
#FormUrlEncoded
#POST("service_name")
void functionName(
#Field("yourarray[]") ArrayList<String> learning_objective_uuids, #Field("user_uuids[]") ArrayList<String> user_uuids, #Field("note") String note,
Callback<CallBackClass> callback
);
You can follow this link.
Or you could use JSONObject like so:
#POST("demo/rest/V1/customer")
Call<RegisterEntity> customerRegis(#Body JsonObject registrationData);
registrationData:
private static JsonObject generateRegistrationRequest() {
JSONObject jsonObject = new JSONObject();
try {
JSONObject subJsonObject = new JSONObject();
subJsonObject.put("email", "abc#xyz.com");
subJsonObject.put("firstname", "abc");
subJsonObject.put("lastname", "xyz");
jsonObject.put("customer", subJsonObject);
jsonObject.put("password", "password");
} catch (JSONException e) {
e.printStackTrace();
}
JsonParser jsonParser = new JsonParser();
JsonObject gsonObject = (JsonObject) jsonParser.parse(jsonObject.toString());
return gsonObject;
}
You can define an object reflecting the structure of the POST body:
#POST("/pathtopostendpoint")
Call<ResponseObject> postFunction(#Body final RequestBody body);
with your RequestBody being defined as following (if you use the GSON converter, tweak the naming of the field with #SerializedName):
class RequestBody {
String tips;
String amount;
int[] serviceIds;
RequestBody(final String tips, final amount String, final int[] serviceIds) {
this.tips = tips;
this.amount = amount;
this.serviceIds = serviceIds;
}
}
and build the request call like that:
final Call<ResponseObject> call = retrofitService.postFunction(
new RequestBody("10", "100", new int[]{ 3, 1, 2 })
);

How to obtain and convert custom json data as strings in android

I've googled around and found many tutorials(duplicates) and tips about json for android, but I find it difficult to perceive. I find it hard to get the score and the names as strings from the following json that I've retrieved from my database. I tried to get the result object first and get the names and scores but not certain how I can get manage to get it from [{},{}].
Are there some easy examples or tips? It sounds silly, but I need your help. I would like to hear from you!
{
"result": [
{
"id": "3",
"name": "Bobby",
"score": "44"
},
{
"id": "2",
"name": "Mike",
"score": "10"
}
]
}
Let,
String s = "{"result": [{"id": "3","name": "Bobby","score": "44"},{"id": "2","name": "Mike","score": "10"}]}";
JSONObject jsonObject = new JSONObject(s);
JSONArray result= jsonObject .getJSONArray("result");
for(int i = 0; i < result.length(); i++) {
JSONObject json = result.getJSONObject(i);
String name = json.getString("name");
String score = json.getString("score");
}
it's so simply
Just do like this
first make a model for according to your need like id, name and score
then use this
JSONObject jObj = new JSONObject(response.toString());
JSONArray results = jObj.getJSONArray("result");
now the values are in array use that array to show values
In json {} means object and [] means array.
First you should create a Json object from your string. Then get result as an array. In result you have tow objects that you can get them with their index.
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray result= jsonObject .getJSONArray("result");
// Now we can iterate through the array
for(int i = 0; i < result.length(); i++) {
JSONObject item = (JSONObject) result.get(i);
String name = item.getString("name");
String score = item.getString("score");
}
Use GSON to deserialize from JSON to a Plain Old Java Object (POJO).
Include GSON library in your Android project:compile 'com.google.code.gson:gson:2.8.0'
Create your JAVA POJO model:
public class MyClass {
#SerializedName("result")
private List mResult;
public List<Result> getResults() {
return mResult;
}
private static class Result {
#SerializedName("id")
private String mId;
#SerializedName("name")
private String mName;
#SerializedName("score")
private String mScore;
public String getId() {
return mId;
}
public String getName() {
return mName;
}
public String getScore() {
return mScore;
}
}
}
Deserialize your JSON to your POJO object:
Gson gson = new Gson();
gson.fromJson(you_json_string, MyClass.class);
Once you have your deserialized object you just need to call your getters:
getResults().get(0).getScore()

Android gson AbstractAdapter.serialize is not called (polymorphic serialization)

Good day my fellow developers,
I'm struggling with gson lib from google in my Android app. I'm trying to serialize a list of objects to Json string, however without luck. My inheritance hierarchy looks like this:
interface IFloorPlanPrimitive
abstract class FloorPlanPrimitiveBase implements IFloorPlanPrimitive
class Wall extends FloorPlanPrimitiveBase
class Mark extends FloorPlanPrimitiveBase
Pretty simple. There are some of fields in each class. I searched for the matter on the web and added this adapter class to facilitate with serializing/deserializing. Currently I'm unable to serialize, so let's focus on that.
public class FloorPlanPrimitiveAdapter implements
JsonSerializer<FloorPlanPrimitiveBase>, JsonDeserializer<FloorPlanPrimitiveBase> {
#Override
public JsonElement serialize(FloorPlanPrimitiveBase src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("type", new JsonPrimitive(src.getClass().getSimpleName()));
result.add("properties", context.serialize(src, src.getClass()));
return result;
}
#Override
public FloorPlanPrimitiveBase deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String type = jsonObject.get("type").getAsString();
JsonElement element = jsonObject.get("properties");
try {
final String packageName = IFloorPlanPrimitive.class.getPackage().getName();
return context.deserialize(element, Class.forName(packageName + '.' + type));
} catch (ClassNotFoundException cnfe) {
throw new JsonParseException("Unknown element type: " + type, cnfe);
}
}
}
And this is how I use it:
public String getFloorPlanAsJSon() {
GsonBuilder gsonBilder = new GsonBuilder();
gsonBilder.registerTypeAdapter(FloorPlanPrimitiveBase.class, new FloorPlanPrimitiveAdapter());
Gson gson = gsonBilder.create();
List<IFloorPlanPrimitive> floorPlan = mRenderer.getFloorPlan();
String jsonString = gson.toJson(floorPlan);
return jsonString;
}
From a simple debug I see that serialize method of FloorPlanPrimitiveAdapter is not being called when serializing and thus I don't get those "type" and "properties" fields in Json. Instead I get straight-forward Json string. I suppose this is due to mismatch in types. I'm asking to serialize IFloorPlanPrimitive, but instead pass FloorPlanPrimitiveBase which implements this interface. My expectation was that it should work :)
Can anyone point on how to deal with serialization and deserialization in this situation? How to overcome that "mismatch"?
Thank you in advance,
Kind regards, Greg.
Good day,
I want to share my solution to my own problem. I hope this will be helpful for others. Also, I would like to know if this solution has any flaws.
So, first the usage. I looked into another answer on SO (linked below). Also this issue on Gson github was also helpful (in particular I learnt there to pass a type parameter into toJson() method:
public String getFloorPlanAsJSon() {
GsonBuilder builder = new GsonBuilder();
final Type type = (new TypeToken<List<FloorPlanPrimitiveBase>>() {}).getType();
builder.registerTypeAdapter(type, new FloorPlanAdapter());
Gson gson = builder.create();
List<IFloorPlanPrimitive> floorPlan = mRenderer.getFloorPlan();
String jsonString = gson.toJson(floorPlan, type);
return jsonString;
}
And now the Adapter I actually took from this SO answer (beware it has bug in it - the name of class put into Json is ArrayList instead of class of the element):
public class FloorPlanAdapter implements JsonSerializer<List<FloorPlanPrimitiveBase>> {
private static final String CLASSNAME = "CLASSNAME";
private static final String INSTANCE = "INSTANCE";
#Override
public JsonElement serialize(List<FloorPlanPrimitiveBase> src, Type typeOfSrc,
JsonSerializationContext context) {
JsonArray array = new JsonArray();
for (FloorPlanPrimitiveBase primitiveBase : src) {
JsonObject primitiveJson = new JsonObject();
String className = primitiveBase.getClass().getCanonicalName();
primitiveJson.addProperty(CLASSNAME, className);
JsonElement elem = context.serialize(primitiveBase);
primitiveJson.add(INSTANCE, elem);
array.add(primitiveJson);
}
return array;
}
}
As you can see it loops over all objects in List<> and processes it just like FloorPlanPrimitiveBaseAdapter in my original question.
This is how I deserialize it:
#Override
public List<FloorPlanPrimitiveBase> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final String packageName = IFloorPlanPrimitive.class.getPackage().getName();
List<FloorPlanPrimitiveBase> result = new ArrayList<>();
JsonArray jsonArray = json.getAsJsonArray();
for (JsonElement element : jsonArray) {
final JsonObject asJsonObject = element.getAsJsonObject();
String className = asJsonObject.get(CLASSNAME).getAsString();
JsonElement serializedInstance = asJsonObject.get(INSTANCE);
Class<?> klass;
try {
klass = Class.forName(packageName + '.' + className);
final FloorPlanPrimitiveBase deserializedInstance = context.deserialize(serializedInstance, klass);
result.add(deserializedInstance);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return result;
}

How to parse JSONArray with variable key (GSON)?

My json is :
{"array":[{"US":"id_123"},{"UK":"id_112"},{"EN":"id_1112"}...]}
My classes are:
class LocaleResponce implements Serializable{
#SerializedName("array")
List<Locale> array;
}
class Locale implements Serializable{
#SerializedName("title")
String title;
#SerializedName("id")
String id;
}
I'm tried to make this:
Gson gson = new Gson();
Type type = new TypeToken<LocaleResponce >(){}.getType();
LocaleResponce response = gson.fromJson(cacheJsonObject.toString(), type);
it doesn't work or is it an issue of server?
It can be achieved by creating custom JsonDeserializer.
Your deserializer class will look something like
public class CityListDeserializer implements JsonDeserializer<List<City>>{
#Override
public List<City> deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<City> cityList = new ArrayList<>();
JsonObject parentJsonObject = element.getAsJsonObject();
Map.Entry<String, JsonElement> entry = parentJsonObject.entrySet().iterator().next();
Iterator<JsonElement> iterator = entry.getValue().getAsJsonArray().iterator();
City city;
while (iterator.hasNext()){
JsonObject cityJsonObject = iterator.next().getAsJsonObject();
for(Map.Entry<String, JsonElement> entry1 : cityJsonObject.entrySet()){
city = new City();
city.cityName = entry1.getKey();
city.id = entry1.getValue().toString();
cityList.add(city);
}
}
return cityList;
}
}
You can use it with
try {
JSONObject object = new JSONObject("{\"array\":[{\"US\":\"id_123\"},{\"UK\":\"id_112\"},{\"EN\":\"id_1112\"}]}");
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(new TypeToken<ArrayList<City>>() {}.getType(), new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
List<City> cityList = gson.fromJson(String.valueOf(object), new TypeToken<ArrayList<City>>() {}.getType());
} catch (JSONException e) {
e.printStackTrace();
}
Your City class will be
public class City {
String cityName;
String id;
}
You can generate classes for Json using websites like http://www.jsonschema2pojo.org/ etc in your case the array array variable, does not have an array of homogeneous objects {"US":"id_123"},{"UK":"id_112"},{"EN":"id_1112"} these are all objects of different DataTypes because, the parameter keys are different, so for parsing this you cannot use a Pojo. The parameters vary from UK US EN etc, the solution here is either to ask the person who is developing the api to send Json that is Consistent, the array that you have received is not type safe, if you want to use this in Java you have to write lots of lines of code. For example you can get the value of the parameter "UK" like this
cacheJsonObject.get("array").getAsJsonArray().get(1).get("UK").getAsString();
This would return the value id_112 for instance.

convert ArrayList<MyCustomClass> to JSONArray

I have an ArrayList that I use within an ArrayAdapter for a ListView. I need to take the items in the list and convert them to a JSONArray to send to an API. I've searched around, but haven't found anything that explains how this might work, any help would be appreciated.
UPDATE - SOLUTION
Here is what I ended up doing to solve the issue.
Object in ArrayList:
public class ListItem {
private long _masterId;
private String _name;
private long _category;
public ListItem(long masterId, String name, long category) {
_masterId = masterId;
_name = name;
_category = category;
}
public JSONObject getJSONObject() {
JSONObject obj = new JSONObject();
try {
obj.put("Id", _masterId);
obj.put("Name", _name);
obj.put("Category", _category);
} catch (JSONException e) {
trace("DefaultListItem.toString JSONException: "+e.getMessage());
}
return obj;
}
}
Here is how I converted it:
ArrayList<ListItem> myCustomList = .... // list filled with objects
JSONArray jsonArray = new JSONArray();
for (int i=0; i < myCustomList.size(); i++) {
jsonArray.put(myCustomList.get(i).getJSONObject());
}
And the output:
[{"Name":"Name 1","Id":0,"Category":"category 1"},{"Name":"Name 2","Id":1,"Category":"category 2"},{"Name":"Name 3","Id":2,"Category":"category 3"}]
If I read the JSONArray constructors correctly, you can build them from any Collection (arrayList is a subclass of Collection) like so:
ArrayList<String> list = new ArrayList<String>();
list.add("foo");
list.add("baar");
JSONArray jsArray = new JSONArray(list);
References:
jsonarray constructor:
http://developer.android.com/reference/org/json/JSONArray.html#JSONArray%28java.util.Collection%29
collection:
http://developer.android.com/reference/java/util/Collection.html
Use Gson library to convert ArrayList to JsonArray.
Gson gson = new GsonBuilder().create();
JsonArray myCustomArray = gson.toJsonTree(myCustomList).getAsJsonArray();
As somebody figures out that the OP wants to convert custom List to org.json.JSONArray not the com.google.gson.JsonArray,the CORRECT answer should be like this:
Gson gson = new Gson();
String listString = gson.toJson(
targetList,
new TypeToken<ArrayList<targetListItem>>() {}.getType());
JSONArray jsonArray = new JSONArray(listString);
public void itemListToJsonConvert(ArrayList<HashMap<String, String>> list) {
JSONObject jResult = new JSONObject();// main object
JSONArray jArray = new JSONArray();// /ItemDetail jsonArray
for (int i = 0; i < list.size(); i++) {
JSONObject jGroup = new JSONObject();// /sub Object
try {
jGroup.put("ItemMasterID", list.get(i).get("ItemMasterID"));
jGroup.put("ID", list.get(i).get("id"));
jGroup.put("Name", list.get(i).get("name"));
jGroup.put("Category", list.get(i).get("category"));
jArray.put(jGroup);
// /itemDetail Name is JsonArray Name
jResult.put("itemDetail", jArray);
return jResult;
} catch (JSONException e) {
e.printStackTrace();
}
}
}
With kotlin and Gson we can do it more easily:
First, add Gson dependency:
implementation "com.squareup.retrofit2:converter-gson:2.3.0"
Create a separate kotlin file, add the following methods
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
fun <T> Gson.convertToJsonString(t: T): String {
return toJson(t).toString()
}
fun <T> Gson.convertToModel(jsonString: String, cls: Class<T>): T? {
return try {
fromJson(jsonString, cls)
} catch (e: Exception) {
null
}
}
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
Note: Do not add declare class, just add these methods, everything will work fine.
Now to call:
create a reference of gson:
val gson=Gson()
To convert array to json string, call:
val jsonString=gson.convertToJsonString(arrayList)
To get array from json string, call:
val arrayList=gson.fromJson<ArrayList<YourModelClassName>>(jsonString)
To convert a model to json string, call:
val jsonString=gson.convertToJsonString(model)
To convert json string to model, call:
val model=gson.convertToModel(jsonString, YourModelClassName::class.java)
Add to your gradle:
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
Convert ArrayList to JsonArray
JsonArray jsonElements = (JsonArray) new Gson().toJsonTree(itemsArrayList);
I know its already answered, but theres a better solution here use this code :
for ( Field f : context.getFields() ) {
if ( f.getType() == String.class ) || ( f.getType() == String.class ) ) {
//DO String To JSON
}
/// And so on...
}
This way you can access variables from class without manually typing them..
Faster and better ..
Hope this helps.
Cheers. :D
Here is a solution with jackson:
You could use the ObjectMapper to receive a JSON String and then convert the string to a JSONArray.
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONArray;
List<CustomObject> myList = new ArrayList<>();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(myList);
JSONArray jsonArray = new JSONArray(jsonString);
Improving on OP's answer when there are a lot of fields.
could cut down some code with field enumeration ... ( but know that reflection is slower.)
public JSONObject getJSONObject() {
JSONObject obj = new JSONObject();
Field[] fields = ListItem.class.getDeclaredFields();
for (Field f : fields) {
try {
obj.put(f.getName(), f.get(ListItem.this));
} catch (JSONException | IllegalAccessException e) {
}
}
return obj;
}

Categories

Resources