I have a class where i have a field named "list_elements" as String.
This is a jsonObject in my HttpResponse, so gson serialization want parse it to OBject instead of as String.
I can i force Gson to parse this as String ?
Thank's
You can implement your own deserializers. Here is an example:
import com.google.gson.JsonDeserializer;
public class MyModelDeserializer implements JsonDeserializer<MyModel> {
#Override
public MyModel deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject aJson = json.getAsJsonObject();
String myStringObject = aJson.get("myJsonObjectKeyWhichIwantToParseLikeString").getAsJsonObject().toSttring()
MyModel myModel = new MyModel();
myModel.setMyStringObject(myStringObject);
//Dont forget to deserialize and set in myModel another fields from json if needed.
return myModel;
}
}
and don't forget to register your deserializer in gson builder. You can do this in that way:
Gson gson = new GsonBuilder()
...
.registerTypeAdapter(MyModel.class, new MyModelDeserializer())
.create()
Related
When parsing JSON in Android using the GSON parser, I'd like to implement a rule that will exclude any objects from being created based on property value. For example:
{"people": [
{"first_name": "Bob"},
{"first_name": "Bob", "last_name": "Loblaw"}]}
I want to exclude the first person object because it doesn't have a last name property.
Is this possible at parse time?
It is possible with JsonDeserializer.
Suppose you would have POJOs like
public class Response {
#Getter
private List<Person> people = new ArrayList<>();
}
and
public class Person {
#Getter #Setter
private String first_name, last_name;
}
Creating JsonDeserializer like
public class PersonResponseDeserializer implements JsonDeserializer<Response> {
// Create a new gson to make the default parsing for response object
private final Gson gson = new Gson();
#Override
public Response deserialize(JsonElement json, Type typeOfT
, JsonDeserializationContext context) throws JsonParseException {
Response r = gson.fromJson(json, typeOfT);
// Remove all persons from R that have last name null
r.getPeople().removeAll(
r.getPeople().stream().filter( p -> p.getLast_name() == null )
.collect(Collectors.toSet())
);
return r;
}
}
could then be used like
Gson gson = new GsonBuilder()
.registerTypeAdapter(Response.class, new PersonResponseDeserializer())
.create();
Response r = gson.fromJson(s, Response.class);
So this is if it is required to be done at the parse time. Maybe it is otherwise better to loop the People after parsing and exclude Persons without last name then.
I have the following json input. And know i am using Gson to parse.
{
“type”: “type1”,
“date”: “Tue, 16 May 2017 07:09:33 +0000”,
“body”:
{
“formatA_1”: “aaa”,
“formatA_2”: “bbbcccddd”
}
"other": "info"
}
public class Data {
private String type;
private Long date;
private Body body;
private String other;
...
}
As i want to convert the date to long, So i implement the custom DateDeserializer.
public class DateDeserializer implements JsonDeserializer<Long> {
#Override
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return DateConvertUtils.convertStringDatetoLong(json.getAsString(), DateConvertUtils.SERVER_DATE_FORMAT);
}
}
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Long.class, new DateDeserializer());
Gson gson = gsonBuilder.create();
Data data = gson.fromJson(json, Data.class);
This is working. But i wonder, how the Gson knows that only the "date" element needs to use the DateDeserializer? How it knows that other elements no need to use DateDeserializer?
If I put more other custom deserializers, how it would know which element is to use which deserializer?
Thanks a lot.
Gson uses the last added deserializer for given type and uses the deserializer for all cases. In your case, it will use your deserializer for any and all Longs
I am making an API call to Facebook and receiving the following Json object:
{"first_name":"FirstName",
"last_name":"LastName",
"email":"email#email.com",
"picture":{"data":{"is_silhouette":true,"url":"pictureUrl"}},"id":"12345"}
Instead of deserializing the object manually, I am currently using Gson for it, like this:
FacebookProfileModel facebookProfileModel = new Gson().fromJson(object.toString(), FacebookProfileModel.class);
Here's how my POJO looks like:
#SerializedName("first_name")
String mFirstName;
#SerializedName("last_name")
String mLastName;
#SerializedName("email")
String mEmail;
#SerializedName("url")
String mUrl;
Obviously, I am receiving all the values except for the url, since the value is in 2 Json objects: picture and data. I guess one possible solution but not the best would be to create the Picture object within the Facebook Model and then the Data object within the Picture object but feels bad creating 2 more pojos for a String. Any other solutions?
There is no annotation based solution for this. However, the custom de-serializer would resolve this problem.
Custom Deserializer:-
public class FacebookProfileModelDeserializer implements JsonDeserializer<FacebookProfileModel> {
#Override
public FacebookProfileModel deserialize(JsonElement paramJsonElement, Type paramType,
JsonDeserializationContext paramJsonDeserializationContext) throws JsonParseException {
String url = paramJsonElement.getAsJsonObject().get("picture").getAsJsonObject().get("data").getAsJsonObject()
.get("url").getAsString();
FacebookProfileModel facebookProfileModel = new Gson().fromJson(paramJsonElement.getAsJsonObject(),
FacebookProfileModel.class);
facebookProfileModel.setmUrl(url);
return facebookProfileModel;
}
}
Main method:-
public static void main(String[] args) {
String jsonString = "{\"first_name\":\"FirstName\",\"last_name\":\"LastName\",\"email\":\"email#email.com\",\"picture\":{\"data\":{\"is_silhouette\":true,\"url\":\"pictureUrl\"}},\"id\":\"12345\"}";
Gson gson = new GsonBuilder()
.registerTypeAdapter(FacebookProfileModel.class, new FacebookProfileModelDeserializer())
.create();
FacebookProfileModel faceBookProfileModel = gson.fromJson(jsonString, FacebookProfileModel.class);
System.out.println(faceBookProfileModel.toString());
}
JSON structure looks like the following:
"blabla": 1234,
"blabla2": "1234",
"object": {
"property1": "1234",
"property2": "blablab",
"property3": "12345",
"property4": Date object,
}
}
Due to this structure, I have implemented a custom deserializer and passed it in the TypeAdapter:
.registerTypeAdapter(Date.class, new DateDeserializer())
.registerTypeAdapter(GenericNotificationResponse.class, new NotificationDeserializer())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
public class NotificationDeserializer implements JsonDeserializer<GenericNotificationResponse> {
#Override
public GenericNotificationResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject content = json.getAsJsonObject();
GenericNotificationResponse message = new Gson().fromJson(json, typeOfT);
JsonElement notification = content.get("notification");
if (message.mType == 1)
message.mNotification = (new Gson().fromJson(notification, Model1.class));
else if (message.mType == 2)
message.mNotification = (new Gson().fromJson(notification, Model2.class));
return message;
}
}
And the deserialization of the inner object goes fine. Until recently, when I changed the model and started receiving a Date object as well, as shown in the JSON structure, the last property. For some reason, it cannot parse it and it throws an error, so it seems like the DateDeserializer that I'm passing in the TypeAdapter is not called due to the these lines:
message.mNotification = (new Gson().fromJson(notification, Model1.class));
message.mNotification = (new Gson().fromJson(notification, Model2.class));
The DateDeserializer works since I'm using it within other models and it does the trick. Is there any way I can make the deserialization of the date property in the inner json Object? Thank you!
When you do this:
message.mNotification = (new Gson().fromJson(notification, Model1.class));
You are deserializing with a new Gson() instance that does not have the DateDeserializer.
Try something like this:
new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create().fromJson(notification, Model1.class));
Same thing for Model2 obviously.
My class is like:
class Foo {
public String duration;
public String height;
}
And my json data looks like
{"duration":"12200000", "height":"162"}
Now I want to deserialize it by
Foo foo = gson.fromJson(jsonStr, Foo.class);
So that,
foo.duration is "20 mins" (number of minutes),
foo.height is "162cm"
Is this possible to do using Gson?
Thanks!
GSON allows creation of custom deserializers/serializers. Try to read here.
Sorry for without an example.
class FooDeserializer implements JsonDeserializer<Foo>{
#Override
public Foo deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonObject jo = (JsonObject)json;
String a = jo.get("duration").getAsString()+" mins";
String b = jo.get("height").getAsString() + " cm";
//Should be an appropriate constructor
return new Foo(a,b);
}
}
then:
Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, foo.new FooDeserializer()).create();
and you should receive result as you wish it to get using fromJson(...).