What is the basic purpose of #SerializedName annotation in Android using Gson - java

What is the basic purpose of #SerializedName annotation in Android using Gson?
Give me some different examples. I can't understand the main purpose of using it.

Java class example,
public class Person {
#SerializedName("name")
private String personName;
#SerializedName("bd")
private String birthDate;
}
This class has two fields that represent the person name and birth date of a person. These fields are annotated with the #SerializedName annotation. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field personName is represented as name in JSON.
JSON Example,
{
"name":"chintan",
"bd":"01-01-1990"
}

There are already few answers here,but I would like to add that if you are using ProGuard to Obfuscate your code & don't use #SerializedName("name") in your model class, then your GSON won't work. Because due to obfuscation, your variable names might have changed from String name to String a resulting into broken GSON parsing as GSON will look for key a into json & it will fail.
By specifying #SerializedName, GSON will not look in json based on variable name & will just use specified #SerializedName.
Of Course you can tell proguard to not obfuscate your model, but if you would like to have model obfuscated, then you must specify #SerializedName

Using #SerializedName you are actually telling the Parser when receiving a callback from the server i.e. of a Json format:
{
"name":"John Doe",
}
that when Serializing or Deserializing an object to instead of searching for a key named: "userName", in the Json response, to search for "name".
#SerializedName("name")
var userName: String,
This is good because you may have a model that you would like it to have its members being called with whatever you like.

You can instruct Proguard to not obfuscate your data classes by specifying #Keep on top of the class. This will neither remove nor obfuscate your class. No need to add #SerializedName to each and every field explicitly if the field name is similar to the Json key being used for it.

Let's say in a real-world scenario, your backend dev is giving you this response for an API request you make
{
"name":"John Doe",
"id":"1478"
}
Now, in the data class you make to handle this, there might be chances you want to specify a different variable name at Android side for the fields "name" and "id" that you are getting from backend.
#SerializedName comes to rescue here.
You just need to specify the actual key value you will be getting from backend in the #SerializedName (which will be used to serialize and deserialize) and then you can use a variable name of your choice that stores that value received from the operation.
For example, for the JSON I mentioned earlier, here is how its data class will look like:
data class User(
#SerializedName("name") val userName: String,
#SerializedName("id") val userId: Int
)
Here name, id is used in #SerializedName because it's the backend key.
But I have used userName, userId to store those values.

Related

Convert an external POJO as Map type in DynamoDBEnhancedClient

DynamoDBEnchanced api provides with #DynamoDBBean that is placed on the POJO to save complex objects into dynamodb without having to externally use ways like ObjectMapper to convert them into JSON strings and save. #DynamoBean allows to save the objects in the form of Map i.e M type I have a below POJO which I want to save in dynamodb, however there is an Address var which is of type that is included as jar and we cannot modify its source code. And hence cannot add #DynamoDBBean on it to save it as M type.
Due to which I have to add an attributeconverter to convert that POJO to json string which defeats the whole purpose. Is there any other way to save the external POJO as M type without using converters? Any other annotation that can be placed on the field?
Entity.java
#DynamoDBBean
class Entity
{
String name
String id
Address address
}
Address.java
class Address
{
String street
long streetnumber
}

Jsonkey in Api Response has $

I'm basically using retrofit to create a request to a server, however the date is stored in mongodb and the request returns a response that contiants $date, is there a way to retrieve it?
I'm assuming from the question title that you mean there's a json key with a dollar sign and I'll assume you're using Gson too, because that's common with Retrofit. If so, then you're looking for SerializedName
This annotation lets you specify the name in the json for the key. So in your case you'd want to add it to your model. Something like:
public class Foo {
#SerializedName("$date")
private String date;
}
in kotlin:
data class foo(
#SerializedName("\$date")
val date: String)
This annotation is used by Gson to serialize and deserialize the object into and from json.
I'm sure other libraries that can be plugged into retrofit have something similar.
Also note that on Android this annotation is very handy, because of the obfuscation tools. Usually the models are obfuscated and the variable names change. If you want to keep the right names then this is an approach to it.

Object serialization to json, certain fields only

I have a large nested object. I want to serialise this object in the JSON string, however I need only certain fields to be included. Problem here is that fields could change very frequently and I want to build it in a way that could help me easy include or exclude fields for serialisation.
I know that I can write a lot of code to extract certain fields and build JSON "manually". But I wonder if there are any other elegant way to achieve similar outcome but specifying a list of required fields?
For example having following object structure I want include only id and name in the response:
class Building {
private List<Flat> flats;
}
class Flat {
private Integer id;
private Person owner;
}
class Person {
private String name;
private String surname;
}
Json:
{
"flats" : [
{
"flat":
{
"id" : "1",
"person" : {
"name" : "John"
}
}
}
]
}
You can use gson for serializing/deserializing JSON.
Then you can include the #Expose annotation to use only the fields you require.
Be sure to also configure your Gson object to only serialize "exposed" fields.
Gson gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Alternative:
You can actually do it the inverse way, marking fields which will not be exposed. You can do this with the transient keyword.
So whatever you want to ignore just add transient to it. Here's how it works on gson.
PS: This works on most Java JSON serializers too.
Using com.fasterxml.jackson.annotation.JsonIgnore is another way to achieve this.
import com.fasterxml.jackson.annotation.JsonIgnore;
class Person {
private String name;
#JsonIgnore
private String surname;
}
It will ignore the surname when the parser converts the bean to json.
Similar annotation will be available in other json processing libraries.
If using Gson, study how to use ExclusionStrategy & JsonSerializer.
Using those is a more flexible way to control serialization since it allows to decide per serialization what to serialize.
Using annotations requires later to add / remove those annotations from fields if there is a need to change what to serialize.
In the case of your example the latter might be more appropriate.
This question might be good startpoint
serialize-java-object-with-gson

how to convert json property like "oData.type" to java object [duplicate]

What is the basic purpose of #SerializedName annotation in Android using Gson?
Give me some different examples. I can't understand the main purpose of using it.
Java class example,
public class Person {
#SerializedName("name")
private String personName;
#SerializedName("bd")
private String birthDate;
}
This class has two fields that represent the person name and birth date of a person. These fields are annotated with the #SerializedName annotation. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field personName is represented as name in JSON.
JSON Example,
{
"name":"chintan",
"bd":"01-01-1990"
}
There are already few answers here,but I would like to add that if you are using ProGuard to Obfuscate your code & don't use #SerializedName("name") in your model class, then your GSON won't work. Because due to obfuscation, your variable names might have changed from String name to String a resulting into broken GSON parsing as GSON will look for key a into json & it will fail.
By specifying #SerializedName, GSON will not look in json based on variable name & will just use specified #SerializedName.
Of Course you can tell proguard to not obfuscate your model, but if you would like to have model obfuscated, then you must specify #SerializedName
Using #SerializedName you are actually telling the Parser when receiving a callback from the server i.e. of a Json format:
{
"name":"John Doe",
}
that when Serializing or Deserializing an object to instead of searching for a key named: "userName", in the Json response, to search for "name".
#SerializedName("name")
var userName: String,
This is good because you may have a model that you would like it to have its members being called with whatever you like.
You can instruct Proguard to not obfuscate your data classes by specifying #Keep on top of the class. This will neither remove nor obfuscate your class. No need to add #SerializedName to each and every field explicitly if the field name is similar to the Json key being used for it.
Let's say in a real-world scenario, your backend dev is giving you this response for an API request you make
{
"name":"John Doe",
"id":"1478"
}
Now, in the data class you make to handle this, there might be chances you want to specify a different variable name at Android side for the fields "name" and "id" that you are getting from backend.
#SerializedName comes to rescue here.
You just need to specify the actual key value you will be getting from backend in the #SerializedName (which will be used to serialize and deserialize) and then you can use a variable name of your choice that stores that value received from the operation.
For example, for the JSON I mentioned earlier, here is how its data class will look like:
data class User(
#SerializedName("name") val userName: String,
#SerializedName("id") val userId: Int
)
Here name, id is used in #SerializedName because it's the backend key.
But I have used userName, userId to store those values.

Limiting Fields in JSON Response for REST API?

I am using Spring and Java and implementing REST Based services. I have a set of developers who develop for mobile,iPad and Web too. Consider I have a bean
Class User{
private String Name;
private Integer id;
private String photoURL;
private ArrayList<String> ProjectName;
private ArrayList<String> TechnologyList;
private ArrayList<String> InterestList;
//Getters and setters
}
While the Web Developers need the entire fields and mobile developers just require two fields from it whereas the iPad requires something in between mobile and web.
Since I am using jackson as a parser, is there a way where while requesting to the controller I can specify which all data I require and avoid the others. For example consider I do a GET request like
GET>http://somedomain.com/users?filter=name,id,photoUrl
Which returns me a JSON structure something like
{
"name":"My Name",
"id":32434,
"photoUrl":"/sss/photo.jpg"
}
Sameway if someone asks for some more fields, they could be filtered. Please let me know how this can be done so that my API remains generic and useable for all.
You can achieve what you want but some extra work is necessary. I can offer you two solutions.
1. Return a Map
Simply put every property that is requested into the map.
2. Use Jacksons Object Mapper directly
Jackson lets you set filters that specify which properties are serialized or ignored.
FilterProvider filter = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept(requestedProperties));
String json = objectMapper.writer(filter).writeValueAsString(value);
You can then return the JSON string directly instead of an object.
For both solutions you would ideally write a class that does the job. But if you do that you could as well write your own message converter. You could extend the MappingJackson2HttpMessageConverter, for instance, and overwrite the writeInternal method to suit your needs. That has the big advantage that you don't need to change your controllers.
The straightforward solution is to implement custom Jackson JSON serializer that will get field names that should be serialized from thread local storage and then serialize only fields which names are presented in that context. For other hand, in controller you can grab all allowed fields names from url and store them into thread local context. Hope this helps.

Categories

Resources