In the previous blog posts in this series you've learned how to use Gson to convert Java objects to JSON and vice versa. So far, we've shown you how to set up models and what's important in order to get the correct mapping going. With this blog post we'll start a new multi-post part of this series which will use the GsonBuilder
to customize several pieces of Gson's behavior.
Of course, this isn't the only post in our Gson series. If you're interested in the other topics, check out our series outline:
Gson Series Overview
- Mapping of Enums
- Mapping of Circular References
- Generics
- Custom Serialization for Simplification (Part 1)
- Changing the Default Serialization with Custom Serialization (Part 2)
- Custom Deserialization Basics
- Custom Instance Creator
- Customizing (De)Serialization via @JsonAdapter
- Custom Deserialization for Calculated Fields
- On-The-Fly-Parsing With Streams
- ProGuard Configuration
GsonBuilder Basics
In all the previously published blog posts we've written that you can just get an instance of Gson with Gson gson = new Gson();
. This is totally valid when you need Gson with its standard configurations. However, Gson has a lot of little settings you can change. This is quite convenient if you need to utilize Gson in a way which is slightly non-standard. In order to change certain settings you can use the GsonBuilder
to create a new Gson instance with your customized configuration.
// previously
Gson gson = new Gson();
// now using GsonBuilder
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
The GsonBuilder
class offers a .create()
method which returns a Gson instance. With the Gson instance you can do everything we've shown you before: map all kinds of data from and to JSON.
Naming Policies
The first GsonBuilder
option we want to show you are naming policies. We've always assumed that your Java model files and the JSON payload for request and responses of the API apply the same naming schema. We've shown you how to use @SerializedName to change the serialization of a single model property. However, if your API and your Java models are not agreeing on naming it can be tedious to change hundreds of property names with the @SerializedName
annotation.
Thus, Gson offers configured and custom FieldNamingPolicy
s. For demonstration purposes we adjusted our UserSimple
model and gave the properties some new names:
public class UserNaming {
String Name;
String email_of_developer;
boolean isDeveloper;
int _ageOfDeveloper;
}
As you can see, we're unifying all kind of naming standards in one model. This will result in some funny looking JSONs, but makes it easier to see how the various naming policies will affect them. You can set the policy on the GsonBuilder:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY);
Gson gson = gsonBuilder.create();
All conversions using the above Gson instance will now apply the field naming policy FieldNamingPolicy.IDENTITY
. In the next few sections we'll explore what exactly that means and how the predefined field naming policies behave. Let's start with the easiest one: IDENTITY
.
FieldNamingPolicy - IDENTITY
The field naming policy IDENTITY
uses the exact same naming as the Java model when it serializes an object. No matter with what naming standard you set up your Java models, the JSON will use the same ones. Our strangely named model above would result in the following JSON:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("Norman", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);
The usersJson
would contain:
{
"Name": "Norman",
"_ageOfDeveloper": 26,
"email_of_developer": "norman@futurestud.io",
"isDeveloper": true
}
As you can see, none of the field names changed. It copied the exact names from the model. If you're not setting a policy or don't use the GsonBuilder and directly instantiate a Gson with new Gson()
it'll use this policy.
FieldNamingPolicy - LOWER_CASE_WITH_UNDERSCORES
The second policy we would like to show you is LOWER_CASE_WITH_UNDERSCORES
. The naming is pretty clear, but let's use it on our sample model:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("Norman", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);
The LOWER_CASE_WITH_UNDERSCORES
will split up the property names based on upper characters and replace those upper characters with a lower one leading with a _
. For our model two properties are affected:
{
"name": "Norman",
"_age_of_developer": 26,
"email_of_developer": "norman@futurestud.io",
"is_developer": true
}
The isDeveloper
and _ageOfDeveloper
got split up with _
. Note that the leading _
of _ageOfDeveloper
is still there! If you don't want to use underscores and instead prefer dashes, the next section might be something for you.
FieldNamingPolicy - LOWER_CASE_WITH_DASHES
The third option we would like to show you is LOWER_CASE_WITH_DASHES
. It uses the same system as the previous LOWER_CASE_WITH_UNDERSCORES
, but replaces the field name separation with -
. Let's apply the following code:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("Norman", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);
This will result in a usersJson
with the following content:
{
"name": "Norman",
"_age-of-developer": 26,
"email_of_developer": "norman@futurestud.io",
"is-developer": true
}
Please note how it still only changed the two properties with upper case letters in them. The leading underscore of _ageOfDeveloper
or the underscores of email_of_developer
are not affected! If you need a more strict policy, you can implement your own logic, which we'll show you in a minute. But before moving to custom policies, it's time for the last two predefined ones.
FieldNamingPolicy - UPPER_CAMEL_CASE
The fourth policy is UPPER_CAMEL_CASE
, which makes the first letter upper case. You hopefully know by now how to apply a naming policy using the GsonBuilder
:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("Norman", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);
The resulting usersJson
would be:
{
"Name": "Norman",
"_AgeOfDeveloper": 26,
"Email_of_developer": "norman@futurestud.io",
"IsDeveloper": true
}
You can see that this is the first policy that affects all four properties. It changes all of them to start with an upper case letter, even if the property name starts with a leading _
. This policy doesn't change the separation though. It leaves underscores the same. The next one changes the word separation a bit:
FieldNamingPolicy - UPPER_CAMEL_CASE_WITH_SPACES
The last policy UPPER_CAMEL_CASE_WITH_SPACES
is almost identical to UPPER_CAMEL_CASE
. The code is almost the same anyway:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("Norman", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);
Let's look at the resulting usersJson
:
{
"Name": "Norman",
"_Age Of Developer": 26,
"Email_of_developer": "norman@futurestud.io",
"Is Developer": true
}
As you can see, not much changed from UPPER_CAMEL_CASE
. The only difference is that the two fields, which already had upper case letters, received spaces in between the words.
Interaction with @SerializedName
You might be wondering how the policies interact with @SerializedName
. We've demonstrated the usage of @SerializedName
in an earlier blog post. Let's change our UserNaming
model to utilize @SerializedName
:
public class UserNaming {
String Name;
@SerializedName("emailOfDeveloper")
String email_of_developer;
boolean isDeveloper;
int _ageOfDeveloper;
}
What happens when you apply a naming policy now? The answer is that it'll leave the property with the @SerializedName
untouched. For example, if we use UPPER_CAMEL_CASE
, it'll result in this JSON:
{
"Name": "Norman",
"_AgeOfDeveloper": 26,
"emailOfDeveloper": "norman@futurestud.io",
"IsDeveloper": true
}
The emailOfDeveloper
stayed exactly as in the @SerializedName
annotation and did not get a leading upper case letter.
Custom Field Naming
The provided policies in combination with the @SerializedName
might not be enough to cover your use case. You can implement your own version of the FieldNamingPolicy
. Since you can only pass pre-defined enum
values to the .setFieldNamingPolicy()
method, Gson offers a second method .setFieldNamingStrategy()
.
You can pass an instance of the FieldNamingStrategy
to the appropriate method. The FieldNamingStrategy
class only has a single method. For example, if we would want to remove all underscores, which none of the predefined policies do, we could use the following code snippet:
FieldNamingStrategy customPolicy = new FieldNamingStrategy() {
@Override
public String translateName(Field f) {
return f.getName().replace("_", "");
}
};
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingStrategy(customPolicy);
Gson gson = gsonBuilder.create();
UserNaming user = new UserNaming("Norman", "norman@futurestud.io", true, 26);
String usersJson = gson.toJson(user);
The resulting JSON would not contain any underscores anymore:
{
"Name": "Norman",
"ageOfDeveloper": 26,
"emailOfDeveloper": "norman@futurestud.io",
"isDeveloper": true
}
Gson only accepts one strategy. Thus, you've to implement your logic in a single FieldNamingStrategy
implementation. If you call one of the methods we've shown you above more than once, it'll replace the previous one.
Deserialization
In this blog post we've only looked at the serialization side of things. In other words how does the JSON look like after we've used Gson to convert the data from Java objects. All of these naming policies have the same effect during deserialization. Basically, if you've an API which returns all values in lower case with underscores as separation between words you could use the LOWER_CASE_WITH_UNDERSCORES
as policy and use regular Java naming conventions in your model.
As a simple example, if you've the following JSON:
{
"reviewer_name": "Marcus"
}
You can have the following model:
public class PostReviewer {
String reviewerName;
}
If you apply the correct naming strategy, Gson will do the mapping even though the names are different.
Outlook
In this blog post, you've learned the basics of using the GsonBuilder
. We looked at a first option to customize Gson's behavior. In particular, we've shown you a variety of policies to customize property naming during the (de)serialization of Java objects.
In the next blog post, we'll continue to show you more GsonBuilder
capabilities. Specifically, we'll introduce a way to force Gson to serialize null
values.
If you've feedback or a question, let us know in the comments or on twitter @futurestud_io.
Make it rock & enjoy coding!