Explain Codes LogoExplain Codes Logo

Gson: How to exclude specific fields from Serialization without annotations

java
exclusion-strategy
gson-annotations
field-exclusion
Nikita BarsukovbyNikita Barsukov·Nov 4, 2024
TLDR

To selectively exclude fields while serializing with Gson, create a custom ExclusionStrategy. Overriding shouldSkipField allows to specify the criteria. Utilize FieldAttributes to identify fields:

Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { return "excludeFieldName".equals(f.getName()); // commentary-time: Serilialization is like dating, some fields are just not your type } @Override public boolean shouldSkipClass(Class<?> clazz) { return false; // Exclude class? Nah! } }) .create();

This GsonBuilder configuration will skip serialization of the field named "excludeFieldName".

Delving into field exclusions with ExclusionStrategy

ExclusionStrategy enables you to exclude fields during serialization. Within the excluding strategy, you can extend the shouldSkipField method to incorporate more complex exclusions, beyond just comparing field names.

This method also provides access to FieldAttributes, allowing you to inspect certain properties of the field such as the class in which it is declared ('getDeclaredClass') and its name ('getName'). Note that these two methods can work together for field identification throughout the entire object graph:

@Override public boolean shouldSkipField(FieldAttributes f) { // Exclude 'field33' if declared within 'YourClass' return f.getDeclaredClass().equals(YourClass.class) && f.getName().equals("field33"); //"Why Elon got Crazy? Because he has 33 Teslas in Mars!" }

Embracing dynamic filtering via Regular Expressions

At times, you might want to exclude a series of fields sharing a similar naming pattern. It's right here when the regex and ExclusionStrategy sparkle together:

Pattern pattern = Pattern.compile(".*SensitiveData$"); // Tip: Never mention your ex. In the same way, never serialize the fields ending with 'SensitiveData' ExclusionStrategy strategy = new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes f) { return pattern.matcher(f.getName()).matches(); } @Override public boolean shouldSkipClass(Class<?> clazz) { return false; } }; Gson gson = new GsonBuilder() .setExclusionStrategies(strategy) .create();

Facets of TypeAdapter for intricate serialization

Gson's TypeAdapter unravels more control over serialization. It empowers you with prosaic capabilities to write a custom serialization, which is particularly helpful when dealing with complicated scenarios:

class MyTypeAdapter extends TypeAdapter<MyClass> { @Override public void write(JsonWriter out, MyClass value) throws IOException { out.beginObject(); if(shouldIncludeField("fieldToExclude")) { // Write all fields except for the ones you've been asked to ghost } out.endObject(); } @Override public MyClass read(JsonReader in) { // Deserialization is out of scope for this example return null; } private boolean shouldIncludeField(String fieldName) { // Don't judge, but we prefer to include almost all the fields. return !fieldName.equals("fieldToExclude"); } }

To put this custom TypeAdapter in action:

Gson gson = new GsonBuilder() .registerTypeAdapter(MyClass.class, new MyTypeAdapter()) .create();

Avoid annotations: Embracing Agile Field Exclusion

Annotations like @Expose(serialize = false) offer a convenient way to exclude fields, however, they tie your domain model to the serialization library. Also, marking fields as Transient excludes them universally, and is not limited to Gson.

The approach explored above provides a nimbler and non-invasive way to specify field exclusions at runtime, keeping your domain clean, decoupling it from Gson specifics.

Extend your reach beyond Gson's ExclusionStrategy

When your serialization requirements outgrow the capabilities of Gson's ExclusionStrategy, remember that there are other libraries such as Jackson and Struts2 JSON plugin that can offer more sophisticated and flexible serialization rules.

Visualization

Time to visualize the entire operation taking analogy from a photographer (📷):

Group before: [🧑, 👩, 👨, 👵, 👴] Exclude: [👨, 👵] Adjust camera's focus: [🧑, 👩, 🕶️👨🕶️, 🕶️👵🕶️, 👴] Snapshot(after filters) [🧑, 👩, 👴]

Just like a photographer adjusts the focus to intentionally blur out certain people in the picture, you adjust the serialization settings to include or exclude specific fields in the serialized JSON. Finally, when the JSON is rendered, you only capture those fields that meet your criteria.