GSON / JSON converting from innerJsonObject - android

I need to create the following JSON Object and than convert it to string using the GSON library (toJson(Object)). However, GSON appends the nameValuePair with each JSON Object, what do I need to do?
"Param_1":
{
"SubParam_1": { type: String, required: true }
}
I'm putting these JSONObjects into a ParameterMap (android HTTP Client) and using GSON to convert the map to JSON String.

First of all the JSON "object" you've written is not even valid JSON!
If anything, you could create a JSON like this:
{
"Param_1": {
"SubParam_1": { "type": "String", "required": true }
}
}
And that's very easy, you just need to have the correct class model, something like this:
public class YourClass {
private Param Param_1;
}
public class Param {
private SubParam SubParam_1;
}
public class SubParam {
private String type;
private boolean required;
}
And then you can use the method .toJson(), like this:
Gson gson = new Gson();
String jsonString = gson.toJson(yourObject);

Related

How to write a Pojo using a dynamic key inside JSONarray

I don't even know if this is a valid question but I am having a hard time converting the API result to POJO since some key are dynamic.
{
"data": [{
"something_edit": true
},
{
"test_null": false
}
],
"success": true
}
As you can see the key inside data are dynamic. I tried using jsonschema2pojo or other converter but it is declaring a named variable which is not a good result. BTW I am using retrofit and GSON library
EDIT:
So here is the flow, so the keys are the ones I asked on the API. So for Example I asked something_edit1, something_edit2 and something_edit3. The data result will be.
{
"data": [{
"something_edit1": true
}, {
"something_edit2": false
},
{
"something_edit3": false
}
],
"success": true
}
You can use Json Object or Generics for your condition.
Using Json Object you can check, if key is exist in your json.
if(yourJsonObject.hasOwnProperty('key_name')){
// do your work here
}
Using Generic you have to check, if your Pojo have instance of the
Pojo.
if(YourMainPOJO instanceOf YourChildPojo){
// do your work here
}
Try to view only Generic part in this link.
It's hard to determine or you have to declare all the possible fields in your POJO or write your own json parser extending the Gson Parser or use a JsonElement which can be converted into json array, object and primitive, based on that result you can convert back to some specific pojo.
/**
* this will convert the whole json into map which you can use to determine the json elements
*
* #param json
*/
private void getModelFromJson(JsonObject json) {
Gson gson = new Gson();
Map<String, JsonElement> jsonElementMap = gson.fromJson(json.toString(), new TypeToken<Map<String, JsonElement>>() {
}.getType());
for (Map.Entry<String, JsonElement> jsonElementEntry : jsonElementMap.entrySet()) {
if (jsonElementEntry.getValue().isJsonPrimitive()) {
//json primitives are data types, do something
//get json boolean
//you can here also check if json element has some json object or json array or primitives based on that
//you can convert this to something else after comparison
if (true) {
InterestModelResponse response = gson.fromJson(jsonElementEntry.getValue().getAsJsonObject().toString(), InterestModelResponse.class);
//use your dynamic converted model
}
} else {
//do something else
}
}
}
2 Years ago we did a project in which we had to handle notifications data with different type of objects in same array we handle that while using retrofit
this is our retrofit Creator class
class Creator {
public static FullTeamService newFullTeamService() {
final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
final OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(FullTeamService.HOST)
.client(client)
.addConverterFactory(GsonConverterFactory.create(GsonUtils.get()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(FullTeamService.class);
}
}
and GsonUtils.java is:
public class GsonUtils {
private static final Gson sGson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.registerTypeAdapter(NotificationObject.class, new NotificationDeserializer())
.create();
private GsonUtils() {}
public static Gson get() {
return sGson;
}
}
NotificationObject is something like:
public class NotificationObject {
#SerializedName("ID")
#Expose
private long ID;
#SerializedName("type")
#Expose
private Type type;
#SerializedName("DataObject")
#Expose
private NotificationDataObject dataObject;
public void setDataObject(NotificationDataObject newsFields) {
dataObject = newsFields;
}
#SuppressWarnings("unchecked")
public <T> T getDataObject() {
return (T) dataObject;
}
public enum Type {
#SerializedName("0")
CHAT_MESSAGE,
#SerializedName("10")
GAME_APPLICATION,
#SerializedName("20")
GAME_APPLICATION_RESPONSE,
#SerializedName("30")
GAME_INVITE....
}
}
NotificationDataObject as new class is like:
public class NotificationDataObject {}
and finally NotificationDeserializer is like:
public class NotificationDeserializer implements JsonDeserializer<NotificationObject> {
#Override
public NotificationObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject itemBean = json.getAsJsonObject();
final NotificationObject object = GsonUtils.getSimpleGson().fromJson(itemBean, NotificationObject.class);
switch (object.getType()) {
case CHAT_MESSAGE:
break;
case GAME_APPLICATION:
object.setDataObject(GsonUtils.get().fromJson(itemBean.get("DataObject").getAsJsonObject(),
GameApplicationNotification.class));
break;
case GAME_APPLICATION_RESPONSE:
object.setDataObject(GsonUtils.get().fromJson(itemBean.get("DataObject").getAsJsonObject(),
GameApplicationResponseNotification.class));
break;
case GAME_INVITE:
object.setDataObject(GsonUtils.get().fromJson(itemBean.get("DataObject").getAsJsonObject(),
GameInviteNotification.class));
break;
}
return object;
}
}
Happy coding ...!
any query will be appreciated...

Android Retrofit and GSON: JSON response returns object or string as property value

The JSON data returned from the server can either return an object, or if that object is null, it returns an empty string ("").
My problem is that my DTO expects an object, but it sees a string and crashes.
PersonDTO
data class PersonDto(
#SerializedName("firstName") val first: String,
#SerializedName("lastName") val last: String,
#SerializedName("favorites") val favorites: FavoriteDto,
)
FavoriteDto
class FavoriteDto(
#SerializedName("color") val color: String,
#SerializedName("number") val number: Int
)
Different responses from server
"person" : {
"firstName": "Steve",
"lastName" : "Johnson",
"favorites" : {
"color": "Purple",
"number": 25
}
}
...
"person" : {
"firstName": "Steve",
"lastName" : "Johnson",
"favorites" : ""
}
I've heard that I might need a custom GSON deserializer, but I've never done anything with GSON other than the out of the box stuff - so I was hoping for a nudge in the right direction.
Thanks!
Easiest hack is that you can add extra fields in the class with the same serialised name but with a String data type. Like this -
data class PersonDto(
#SerializedName("firstName") val first: String,
#SerializedName("lastName") val last: String,
#SerializedName("favorites") val favorites: FavoriteDto,
#SerializedName("favorites") val favoritesStr: String,
)
As there is nothing in Gson as "Required" field, you'll just get a null in your deserialized object if something is missing in the JSON. So, if there is an empty string the FavoriteDto object will be null and not null otherwise.
EDIT
I'm adding some Java code that I have written earlier. This might help:
public class PersonDto {
private FavoriteDto favorites;
private String favoritesStr;
public FavoriteDto getResponseDataObject() {
return favorites;
}
public void setResponseDataObject(FavoriteDto favorites) {
this.favorites = favorites;
}
public String getResponseDataString() {
return favoritesStr;
}
public void setResponseDataString(String favoritesStr) {
this.favoritesStr = favoritesStr;
}
Defining the Deserializar:
public static class ArrayObjectDualityDeserializer implements JsonDeserializer<PersonDto> {
public PersonDto deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
PersonDto response = new PersonDto();
JsonObject object = json.getAsJsonObject();
if(object.get("favorites").isJsonArray()) {
} else if(object.get("favorites").isJsonObject()) {
try {
FavoriteDto dtoObject = gson.fromJson(object.get("favorites"), FavoriteDto.class);
response.setResponseDataObject(dtoObject);
} catch (JsonSyntaxException e) {
DebugLogger.e("Error " + e);
}
} else if (object.get("favorites").isJsonNull()) {
} else {
response.setResponseDataString(object.get("favorites").getAsString());
}
}
}
And:
public static Gson gson = new GsonBuilder()
.registerTypeAdapter(PersonDto.class, new ArrayObjectDualityDeserializer())
.create();
Lastly:
private static Retrofit retrofit = null;
private static OkHttpClient.Builder httpClient = null;
private static OkHttpClient session_client = null;
httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new SessionOkHttpInterceptor());
session_client = httpClient.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(session_client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
The answer of #Subrato M. is partially correct. In order to work, you should remove #SerializedName("favorites") annotation from both fields in order to work. In this case, Gson won't throw an error when deserialize multiple json fields named favorites because you don't have any field annotated with that name (also don't name fileds the same as expected field name beucase Gson will try to deserialize). Use the custom deserializer to check if is an object or a string.
Nowadays isn't necessary the #Subrato M's hack, you don't get the right json cause you are missing the data keyword before class FavoriteDto and that is why doesn't exists the get and set methods

Generic Type Gson deserializer

I have an Api which the api looks like this:
If the response is ok the structure will begin with data keyword for example:
{
"data": {
"name": "Rogelio Volkman",
"address": "27299 Will Bridge Suite 058\nWest Reubenhaven, MI 00736",
"lat": 54.65,
"lng": 111.75,
"phone": "+26(4)5015498663"
}
}
And if response is not Ok(status is not 200) response will not container data keyword so response will look like:
{
"message": "404 Not Found",
"status_code": 404
}
Since this structure is a common structure for all models I intended to create a Generic Deserializer for all models.
This looked like:
public class DataObjectDeserializer implements JsonDeserializer<Object> {
#Override
public Objectdeserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException {
// Get the "data" element from the parsed JSON
JsonElement data = je.getAsJsonObject().get("data");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(data, Object.class);
}
}
then registered it as typeAdapter Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(Object.class, new DataObjectDeserializer()).create();
Since every object is an instance of Object I supposed this would work (deserialize my Museum model) but it didn't.
In my second attempt I created an abstract class called DataObjectModel and class Museum extended DataObjectModel. then created anoteher deserailizer like:
public class DataObjectDeserializer implements JsonDeserializer {
#Override
public DataObjectModel deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException {
// Get the "data" element from the parsed JSON
JsonElement data = je.getAsJsonObject().get("data");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(data, DataObjectModel.class);
}
}
And registered it with Gson like Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(DataObjectModel.class, new DataObjectDeserializer()).create();. But this didn't deserialize Museum model either.
The question is: how can I create a deserializer for parent class which would deserialize child class as well (as my second approach) Or How can I create a generic class with Gson so that every tyoe that is wrapped aroung data can be used with it like:
public class DataObjectDeserializer implements JsonDeserializer {
#Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException {
// Get the "data" element from the parsed JSON
JsonElement data = je.getAsJsonObject().get("data");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(data, /* This part not working due to type erasing in java*/ T.calss);
}
}
If you create your response and data structure like this
private class Data {
#SerializedName("name")
private String name;
#SerializedName("address")
private String address;
#SerializedName("lat")
private String lat;
#SerializedName("lng")
private String lng;
#SerializedName("phone")
private String phone;
}
private class Response {
#SerializedName("message")
private String message;
#SerializedName("status_code")
private int statusCode;
#SerializedName("data")
private Data data;
}
you can then do
Response response = new Gson().fromJson(json, Response.class);
if(response.statusCode == 0) {
//everything ok, do something with response.data
} else {
//display response.message, data will be null
}

robospice parse nested object response

I have a JSON object returned by the server like:
{
"success":true,
"value1":1,
"otherValues":{
"var1":1,
"var2":"asd",
"var3":2
}
}
How should I model the response class to accept all the values? For example
package com.phoneme.API.popIndex;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
#JsonIgnoreProperties(ignoreUnknown = true)
public class GetResponse {
private String success
private String value1;
private ??? otherValues;
//GETTERS AND SETTERS of each
}
The response you are trying to decode is not valid JSON. The field names need to be quoted. For example:-
{
"success":true,
"value1":1,
"otherValues":{
"var1":1,
"var2":"asd",
"var3":2
}
}
Using this corrected version of the message, you can generate your POJO here:- http://www.jsonschema2pojo.org/
Good luck!

GSON Deserializing Array of Custom Objects

I am trying to serialize/deserialize JSON in Android using GSON. I have two classes that look like this:
public class Session {
#SerializedName("name")
private String _name;
#SerializedName("users")
private ArrayList<User> _users = new ArrayList<User>();
}
and:
public class User {
#SerializedName("name")
private String _name;
#SerializedName("role")
private int _role;
}
I am using GSON for serializing/deserializing the data. I serialize like so:
Gson gson = new Gson();
String sessionJson = gson.toJson(session);
This will produce JSON that looks like this:
{
"name":"hi",
"users":
[{"name":"John","role":2}]
}
And I deserialize like so:
Gson gson = new Gson();
Session session = gson.fromJson(jsonString, Session.class);
I'm getting an error when I make this call.
DEBUG/dalvikvm(739): wrong object type: Ljava/util/LinkedList; Ljava/util/ArrayList;
WARN/System.err(739): java.lang.IllegalArgumentException: invalid value for field
I don't know what this error means. I don't see myself doing anything gravely wrong. Any help? Thanks!
Change your code to this:
public class Session {
#SerializedName("name")
private String _name;
#SerializedName("users")
private List<User> _users = new ArrayList<User>();
}
It's a good practice use Interfaces, and GSON requires that (at least, without extra configuration).
Gson converts the array "[ ]" in javascript, to a LinkedList object.
In your code, GSON tries to inject a LinkedList in the _users field, thinking than that field its a List.

Categories

Resources