Gson Guidelines for Use (3)

Posted by fothers on Fri, 05 Jul 2019 20:27:14 +0200

Note: This series is based on Gson 2.4.

The main contents of this paper are as follows:

  • Several methods of field filtering
    • Based on @Expose Annotation
    • Version-based
    • Access modifier-based
    • Strategy-based (most commonly used by authors)
  • Field mapping rules between POJO and JSON

I. Several Methods of Field Filtration

Field filtering techniques commonly used in Gson, especially in Android, may require adding fields to POJO s that are set up when dealing with business logic, but obviously they are not needed in the serialization process, and if serialization may cause a problem that is circular references, then before Gson serialization is used In order not to prevent such incidents from happening, you have to deal with them separately.

Take Category as an example.

{
  "id": 1,
  "name": "Computer",
  "children": [
    {
      "id": 100,
      "name": "Notebook"
    },
    {
      "id": 101,
      "name": "Desktop computer"
    }
  ]
}

A big classification can have many small classifications, so obviously when we design a Category class, Category itself can be either a big classification or a small classification.

public class Category {
    public int id;
    public String name;
    public List<Category> children;
}

But in order to handle business, we also need to save the parent category in the subcategory, which will eventually become the following situation

public class Category {
    public int id;
    public String name;
    public List<Category> children;
    //Increased business needs, but no serialization is required
    public Category parent; 
}

But the parent field above is added because of business needs, so serialization is not necessary, so it must be excluded when serialization, so how to exclude eligible fields in Gson? Here are four methods, you can choose the appropriate way according to your needs.

Based on @Expose Annotation

@ Expose provides two attributes with default values, and developers can set different values as needed.


@Expose


@ Expose annotation can be seen from the name to mean exposure, so the annotation is used to expose fields everywhere. But did we not have the @Expose annotation when we used Gson or did we incorrectly serialize it into JSON? Yes, so the annotation uses new Gson() does not work. After all, the most commonly used API is the simplest, so this annotation must be used in conjunction with GsonBuilder.

Usage: Simply put @Expose annotation on the fields that need to be exported, not the fields that need not be exported. Notice that it is not derived without adding.

@Expose //
@Expose(deserialize = true,serialize = true) //Both serialization and deserialization take effect
@Expose(deserialize = true,serialize = false) //Effective upon deserialization
@Expose(deserialize = false,serialize = true) //Effective upon serialization
@Expose(deserialize = false,serialize = false) // It's the same as not writing.

Note: According to the picture above, all attributes with true values can be written off.

Take the example above for example.

public class Category {
    @Expose public int id;
    @Expose public String name;
    @Expose public List<Category> children;
    //No serialization is required, so no @Expose annotation is added.
    //Equivalent to @Expose(deserialize = false,serialize = false)
    public Category parent; 
}

You can't just use new Gson() when you use Gson.

Gson gson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation()
        .create();
gson.toJson(category);
Version-based

Gson provides two annotations @Since and @Until for version-based field export, which are used in conjunction with GsonBuilder.setVersion(Double). @ Since and @Until both receive a Double value.


Since and Until annotations

Usage: When the current version (version set in GsonBuilder) is greater than or equal to the value of Since, the field is exported, and when the value of Until is smaller, the field is exported.

class SinceUntilSample {
    @Since(4)
    public String since;
    @Until(5)
    public String until;
}

public void sineUtilTest(double version){
        SinceUntilSample sinceUntilSample = new SinceUntilSample();
        sinceUntilSample.since = "since";
        sinceUntilSample.until = "until";
        Gson gson = new GsonBuilder().setVersion(version).create();
        System.out.println(gson.toJson(sinceUntilSample));
}
//When version < 4, the result: {"until":"until"}
//When version >= 4 & & version < 5, the result is {"since", "now", "until": "until"}
//When version >= 5, the result is: {since":"since"}

Note: When a field is annotated at the same time, both conditions need to be met at the same time.

Access modifier-based

What are modifiers? public, static, final, private, protected are all, so this is a special way.
How to use it:

class ModifierSample {
    final String finalField = "final";
    static String staticField = "static";
    public String publicField = "public";
    protected String protectedField = "protected";
    String defaultField = "default";
    private String privateField = "private";
}

GsonBuilder.excludeFields WithModifiers is used to build gson, which supports variable parameters of int s. The values are provided by java.lang.reflect.Modifier. The following program excludes privateField, finalField and staticField.

ModifierSample modifierSample = new ModifierSample();
Gson gson = new GsonBuilder()
        .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
        .create();
System.out.println(gson.toJson(modifierSample));
// Results:{"publicField":"public","protectedField":"protected","defaultField":"default"}

So far, one of the annotations provided by Gson has not been introduced by @JsonAdapter, and @JsonAdapter and TypeAdapter will be the main content of the fourth and final article in this series.

Policy-based (custom rules)

The above three methods of excluding fields are introduced. To be honest, I have only used Demo in addition to @Expose. The most frequently used method is the custom rules to be introduced. The advantages are powerful and flexible. The disadvantages are that they are slightly more troublesome than the other three methods, but they are only intended to be slightly troublesome to the other three. Just a little.

The strategy is to use the Exclusion Strategy interface provided by Gson, as well as Gson Builder and related API s. Two are addSerialization Exclusion Strategy and addDeserialization Exclusion Strategy for serialization and deserialization respectively. Here's an example of serialization.

For example:

Gson gson = new GsonBuilder()
        .addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                // Let's decide whether to exclude this field or not. return true is excluded.
                if ("finalField".equals(f.getName())) return true; //Exclude by field name
                Expose expose = f.getAnnotation(Expose.class); 
                if (expose != null && expose.deserialize() == false) return true; //Exclusion by note
                return false;
            }
            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                // To exclude a class directly, return true is to exclude
                return (clazz == int.class || clazz == Integer.class);
            }
        })
        .create();

Is it strong?

II. Field Mapping Rules of POJO and JSON

Before Do you really use Gson? Gson Guidelines (2) The use of the @Serialized Name annotation is introduced when renaming attributes. The content of this section is similar to that of the previous one, but since it's called mapping rules, it's natural to say that there are rules.
In the previous User example, all comments have been removed:

User user = new User("Monster kidou", 24);
user.emailAddress = "ikidou@example.com";

GsonBuilder provides the Field Naming Strategy interface and two methods, setField Naming Policy and setField Naming Strategy.

Default implementation
The GsonBuilder.setFieldNamingPolicy method is used in conjunction with another enumeration class provided by Gson, FieldNamingPolicy, which provides five implementations:

FieldNamingPolicy Result (output emailAddress field only)
IDENTITY {"emailAddress":"ikidou@example.com"}
LOWER_CASE_WITH_DASHES {"email-address":"ikidou@example.com"}
LOWER_CASE_WITH_UNDERSCORES {"email_address":"ikidou@example.com"}
UPPER_CAMEL_CASE {"EmailAddress":"ikidou@example.com"}
UPPER_CAMEL_CASE_WITH_SPACES {"Email Address":"ikidou@example.com"}

Custom Implementation
The GsonBuilder.setFieldNaming Strategy method needs to be used in conjunction with the FieldNaming Strategy interface provided by Gson to implement the correspondence between POJO fields and JSON fields. The above FieldNaming Policy actually implements the FieldNaming Strategy interface, which means that FieldNaming Policy can also use the setFieldNaming Strategy method.

Usage:

Gson gson = new GsonBuilder()
        .setFieldNamingStrategy(new FieldNamingStrategy() {
            @Override
            public String translateName(Field f) {
                //Realize your own rules
                return null;
            }
        })
        .create();

Note: The @Serialized Name annotation has the highest priority and FieldNaming Strategy does not work on fields with @Serialized Name annotations!

Topics: JSON Android Java