Gson Builder — Exclusion Strategies

Datetime:2016-08-23 03:09:26          Topic:          Share

In the previous blog posts, you've learned a few techniques to control which model properties get (de)serialized. So far, this always has been on the property level. You can change the (de)serialization for one element at a time. In this blog post, we'll look at a way to set up more general rules to control which properties get converted.

Of course, this will not be the only post in our Gson series. If you're interested in the other topics, check out our series outline:

Gson Series Overview

  1. Getting Started with Java-JSON Serialization & Deserialization
  2. Mapping of Nested Objects
  3. Mapping of Arrays and Lists of Objects
  4. Mapping of Maps
  5. Mapping of Sets
  6. Mapping of Null Values
  7. Gson Model Annotations — How to Ignore Fields with @Expose
  8. Gson Model Annotations — How to Change the Naming of Fields with @SerializedName
  9. Gson Builder — Basics & Naming Policies
  10. Gson Builder — Force Serialization of null Values
  11. Gson Builder — Exclusion Strategies
  12. Gson Builder — Relax Gson with Lenient
  13. Gson Builder — Special Values of Floats & Doubles
  14. Gson Builder — Model Versioning
  15. Gson Builder — Formatting of Dates & Custom Date/Time Mapping
  16. Gson Builder — Pretty Printing
  17. Gson Builder — HTML Escaping
  18. Gson Advanced — Generics

Go Beyond transient and @Expose with Exclusion Strategies

You've already learned about transient and @Expose , which changes the (de)serialization for single properties. In the next few minutes we'll look at more universal approach. Gson calls them ExclusionStrategies . Of course, you have to set them via GsonBuilder .

Before we go to the specific implementation, let's create a test model. We're going to use a new UserDate model, which has several properties:

public class UserDate {  
    private String _name;
    private String email;
    private boolean isDeveloper;
    private int age;
    private Date registerDate = new Date();
}

Pay extra attention to the property types and their naming. It'll get important in a minute. Let's assume we want to kick out all properties, which are of the Date or boolean type. We can easily do this with ExclusionStrategies . You can implement it via the GsonBuilder :

GsonBuilder gsonBuilder = new GsonBuilder();  
gsonBuilder.setExclusionStrategies(new ExclusionStrategy() {  
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return false;
    }

    @Override
    public boolean shouldSkipClass(Class<?> incomingClass) {
        return incomingClass == Date.class || incomingClass == boolean.class;
    }
});
Gson gson = gsonBuilder.create();

UserDate user = new UserDate("Norman", "norman@futurestud.io", 26, true);  
String usersJson = gson.toJson(user);

The ExclusionStrategy class has two methods you can override. We only used the second option in the example above. We checked if the class is either of the type Date or boolean . If the property is of either type, the function will return true and Gson will ignore it. You can do any class checking in this method. The resulting JSON would only contain the string and int types:

{
  "age": 26,
  "email": "norman@futurestud.io",
  "_name": "Norman"
}

The other method offers the option to exclude properties based on their declaration. For example, if we would want to exclude all properties which contain an underscore _ additionally to the rules above, you could use the following code:

GsonBuilder gsonBuilder = new GsonBuilder();  
gsonBuilder.setExclusionStrategies(new ExclusionStrategy() {  
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getName().contains("_");
    }

    @Override
    public boolean shouldSkipClass(Class<?> incomingClass) {
        return incomingClass == Date.class || incomingClass == boolean.class;
    }
});
Gson gson = gsonBuilder.create();

UserDate user = new UserDate("Norman", "norman@futurestud.io", 26, true);  
String usersJson = gson.toJson(user);

This would result into a pretty short JSON:

{
  "age": 26,
  "email": "norman@futurestud.io"
}

You can use exclusion strategies for a lot of different scenarios. It makes it much easier if you've some universal system of specific (de)serialization exclusions. Please note that you can pass multiple exclusion strategies as a parameter.

If you don't see the point of the exclusion strategy at the moment, that's okay! We'll go much more in depth with more complex types soon. You'll see the value for sure once we moved onto writing our custom adapters. Luckily, with exclusion strategies you can set Gson to ignore any class .

Exclusion Strategies for Serialization or Deserialization Only

In the previous section, we've applied the exclusion strategy to both, serialization and deserialization. If you need an exclusion strategy for only serialization or deserialization, you can use these methods:

  • addSerializationExclusionStrategy()
  • addDeserializationExclusionStrategy() .

The way these two methods work is identical to the previous general approach with setExclusionStrategies() . You can implement and pass the same ExclusionStrategy object.

Exclude Fields Based on Modifiers

As we'veexplained previously, all model fields with a transient modifier are by default ignored during serialization and deserialization.

The GsonBuilder lets you change this behavior. With excludeFieldsWithModifiers() you can customize which modifiers are not included during (de)serialization. The method expects one of the modifiers from the java.lang.reflect.Modifier class.

For example, you could have the following model:

public class UserModifier {  
    private String name;
    private transient String email;
    private static boolean isDeveloper;
    private final int age;
}

If you would want to exclude all fields of the final and static type, but include the transient field, you would need to configure Gson with the GsonBuilder like this:

GsonBuilder gsonBuilder = new GsonBuilder();  
gsonBuilder.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.FINAL);  
Gson gson = gsonBuilder.create();

UserModifier user = new UserModifier("Norman", "norman@fs.io", 26, true);  
String usersJson = gson.toJson(user);

The code above would create this JSON:

{
  "email": "norman@fs.io",
  "name": "Norman"
}

Note how the Gson instance included the email field, even though it's transient . Calling the excludeFieldsWithModifiers() method overwrites the default settings. We've only passed static and final , thus the transient modifier will not be ignored. If you want that all fields are included, no matter of the modifiers, just pass an empty list to excludeFieldsWithModifiers() .

Exclude Fields without @Expose

Finally, one option we're not big fans of, but will mention to give you all the options: excludeFieldsWithoutExposeAnnotation() . As the method name suggests, this excludes all fields which don't have an@Expose annotation.

You can force your application models to have @Expose annotations everywhere and make sure the developer thinks about which field gets (de)serialized.

Outlook

In this blog post, you've learned how you can exclude properties on a more general level. ExclusionStrategies offers two options on how to exclude properties. You can filter based on the class type or the name of the property. There are additional more specialized exclusion strategies.

In the next blog post, we'll look at how flexible Gson is if the JSON isn't structured according to the standard.

If you've feedback or a question, let us know in the comments or on twitter @futurestud_io .

Make it rock & enjoy coding!

Not enough Gson? Buy our book!

Enjoy JSON (de-)serialization in Java. Learn every detail about Gson's capabilities, configuration & customization.

Including a workbook & a cheat sheet!

Available on Leanpub