Статьи

Использование Google GSON: дополнительные вкусности: часть II

Мы продолжаем использовать GSON из предыдущей статьи , также в случае, если вы пропустили первую статью в серии, перейдите по ссылке . Итак, здесь мы идем с другим взносом в серии.

Поддержка версий

Если вы хотите сохранить несколько версий объекта для преобразования JSON, в библиотеке Google GSON есть хорошая аннотация @Since. Эта аннотация может применяться к полям и классам.

Например, предположим, что вы поддерживаете несколько версий REST API и используете JSON в качестве полезной нагрузки конечного ответа. На следующей итерации вашего API вы добавляете некоторые поля для конкретной сущности JSON и не хотите отправлять вновь добавленные поля в предыдущую версию API, после чего появляется аннотация @Since. Давайте посмотрим в следующем листинге, как мы используем эту функцию.

Чтобы использовать эту аннотацию, вы, конечно, должны сконфигурировать экземпляр Gson для конкретной версии, используя GsonBuilder.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Example33 {
  public static void main(String[] args) {
    Gson gson = new GsonBuilder().setVersion(2.0).create();
    String json = gson.toJson(new ExampleClass());
    System.out.println("Output for version 2.0...");
    System.out.println(json);
     
    gson= new GsonBuilder().setVersion(1.0).create();
    json = gson.toJson(new ExampleClass());
    System.out.println("\nOutput for version 1.0...");
    System.out.println(json);
     
    gson= new Gson();
    json = gson.toJson(new ExampleClass());
    System.out.println("\nOutput for No version set...");
    System.out.println(json);
  }
}
 
class ExampleClass{
  String field=  "field";
  // this is in version 1.0
  @Since(1.0) String newField1 = "field 1";
  // following will be included in the version 1.1
  @Since(2.0) String newField2 = "field 2";
}

Выход выше как:

1
2
3
4
5
6
7
8
Output for version 2.0...
{"field":"field","newField1":"field 1","newField2":"field 2"}
 
Output for version 1.0...
{"field":"field","newField1":"field 1"}
 
Output for No version set...
{"field":"field","newField1":"field 1","newField2":"field 2"}

Если вы не указали какую-либо версию, она будет включать все поля независимо от ее версии.

Отключить экранирование HTML

По умолчанию во время преобразования все содержащиеся html-символы будут преобразованы в соответствующий им Unicode, т.е. < to \ u003c, > в \ u003e, & to \ u0026e и т. Д.

Чтобы передать html-символы как есть, вам нужно настроить экземпляр gson на использование метода GsonBuilder # disableHtmlEscaping () .

Следующий листинг показывает использование:

01
02
03
04
05
06
07
08
09
10
11
12
public class Example34 {
  public static void main(String[] args) {
    String str ="<myval>";
    Gson gson = new Gson();
    System.out.println("Normal behaviour...");
    System.out.println(gson.toJson(str));
     
    System.out.println("\nDisabled html escaping...");
    gson = new GsonBuilder().disableHtmlEscaping().create();
    System.out.println(gson.toJson(str));
  }
}

Вывести следующим образом:

1
2
3
4
5
Normal behaviour...
"\u003cmyval\u003e"
 
Disabled html escaping...
"<myval>"

Исключить поля из вывода Json

Для этого у Google GSON есть 4 способа

  1. поля с переходным и статическим модификатором
  2. исключить с полями с определенными модификаторами
  3. Использование аннотации Expose
  4. Определяемые пользователем стратегии исключения

Давайте рассмотрим каждый из них подробно:

  1. поля с переходным и статическим модификатором

    Это поведение по умолчанию, при котором вы изменяете поле с помощью временного модификатора, оно не будет включено, как мы видели в первой статье серии, и, конечно, поле со статическим модификатором также исключается, поскольку оно является частью класса, а не экземпляра.

  2. исключить поля с определенными модификаторами

    Вы можете настроить экземпляр gson так, чтобы он исключал поля с указанными вами модификаторами, например, вы можете исключать / игнорировать поля с защищенным или закрытым модификатором.

    Чтобы использовать это, вам нужно использовать GsonBuilder # excludeFieldsWithModifiers (), как показано в следующей серии листинга.

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    class Developer {
     
      private String name;
      private String classz;
      List<String> languagesKnown;
       
      public Developer() {
        name = "ajduke";
        classz= "Developer";
        languagesKnown = new ArrayList<>();
        languagesKnown.add("Java");
        languagesKnown.add("Scala");
        languagesKnown.add("Ruby");
      }
    }

    Для этого примера мы не включаем приватные поля. Хотя вы можете исключить поля с любыми модификаторами (любые модификаторы, которые применяются к полям)

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    Gson gson = new Gson();
     
    System.out.println("Default behaviour ");
    GsonBuilder gsonBuilder = new GsonBuilder();
    Gson prettyGson = gsonBuilder.setPrettyPrinting().create();
    String json = prettyGson.toJson(new Developer());
    System.out.println(json);
     
    System.out.println("Ignoring/excluding fields ");
     
    GsonBuilder excludeFieldsWithModifiers = gsonBuilder
            .excludeFieldsWithModifiers(Modifier.PRIVATE);
     
    Gson create = excludeFieldsWithModifiers.create();
    String json2 = create.toJson(new Developer());
    System.out.println(json2);

    В следующем выводе вы можете увидеть, что закрытые поля исключены согласно нашей программе, хотя вы можете игнорировать поля, которые могут быть защищены, синхронизированы и т. Д.

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Default behaviour
    {
      "name": "ajduke",
      "classz": "Developer",
      "languagesKnown": [
        "Java",
        "Scala",
        "Ruby"
      ]
    }
     
    Ignoring/excluding fields
    {
      "languagesKnown": [
        "Java",
        "Scala",
        "Ruby"
      ]
    }
  3. Использование аннотации Expose

    Gson также предоставляет аннотацию, которую можно пометить для полей, поэтому эти поля будут исключены из сериализованного вывода.

    Для использования этого нам нужно следующие два

    1. настроить экземпляр gson следующим образом
      Gson gson = GsonBuilder (). ExcludeFieldsWithoutExposeAnnotation (). Create ()
    2. и пометьте поля аннотациями @Expose, которые должны быть включены в окончательный вывод json. Таким образом, тот, который не отмечен, будет исключен

    Следующий список показывает подробное использование

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    class Developer {
      // this field will be included
      @Expose
      private String name;
      private  String classz;
      List<String> languagesKnown;
       
      public Developer() {
        name = "ajduke";
        languagesKnown = new ArrayList<>();
        languagesKnown.add("Java");
        languagesKnown.add("Scala");
        languagesKnown.add("Ruby");
      }
    }
    1
    2
    3
    4
    5
    6
    7
    public class GsonEx {
      public static void main(String[] args) throws IOException {
        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        String json = gson.toJson(new Developer());
        System.out.println(json);
      }
    }

    Выход следующим образом:

    1
    {"name":"ajduke"}
  4. Определяемая пользователем стратегия исключения

    Библиотека Google Gson обеспечивает очень детальный уровень исключений полей в зависимости от типа поля и атрибутов поля.

    Для этого вам необходимо реализовать интерфейс ExclusionStrategy, реализовав два его метода, таких как shouldSkipClass () и shouldSkipField () . Прежний может быть реализован так, что он будет пропускать поля в зависимости от его типа, а позже может быть реализован на основе атрибута поля, такого как его модификатор, его аннотация и т. Д.

    и теперь, после реализации интерфейса ExclusionStrategy, вам нужно передать его в метод GsonBuilder # setExclusionStrategies () для настройки экземпляра gson.

    Ниже приведена минимальная реализация стратегии исключения, в которой мы исключаем, что поля имеют тип String, List, а также поле с аннотацией как устаревшей.

    Обратите внимание на следующую реализацию ExclusionStrategy

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    class ExclusionStrategyImpl implements ExclusionStrategy {
      private final Class<?> classTypeToSkip;
     
      public ExclusionStrategyImpl(Class<?> classTypeToSkip) {
        this.classTypeToSkip = classTypeToSkip;
      }
     
      @Override
      public boolean shouldSkipClass(Class<?> claz) {
        return classTypeToSkip == claz;
      }
     
      @Override
      public boolean shouldSkipField(FieldAttributes fa) {
        return fa.getAnnotation(Deprecated.class) !=null;
      }
    }

    Наш пользовательский класс Developer для показа примера:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    class Developer {
      @Deprecated
      private int count = 45;
      private String name;
      private  String classz;
      List<String> languagesKnown;
       
      public Developer() {
        name = "ajduke";
        classz = Developer.class.getCanonicalName();
        languagesKnown = new ArrayList<>();
        languagesKnown.add("Java");
        languagesKnown.add("Scala");
        languagesKnown.add("Ruby");
      }
    }
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class Ex35 {
     
      public static void main(String[] args) {
        Gson gson = null;
        Developer developer = new Developer();
        String json = null;
        gson = new Gson();
        json = gson.toJson(developer);
        System.out.println("Default behaviuor....");
        System.out.println(json);
         
        // exclude field having String
        gson = new GsonBuilder().setExclusionStrategies(
        new ExclusionStrategyImpl(List.class)).create();
        json = gson.toJson(developer);
        System.out.println("\nExclude fields with type - List");
        System.out.println(json);
         
        // exclude field having List
        gson = new GsonBuilder().setExclusionStrategies(
        new ExclusionStrategyImpl(String.class)).create();
        json = gson.toJson(developer);
        System.out.println("\nExclude fields with type - String");
        System.out.println(json);
      }
    }

    Выход выше, как следует:

    1
    2
    3
    4
    5
    6
    7
    8
    Default behaviuor....
    {"count":45,"name":"ajduke","classz":"in.ajduke.ap013.Developer","languagesKnown":["Java","Scala","Ruby"]}
     
    Exclude fields with type - List
    {"name":"ajduke","classz":"in.ajduke.ap013.Developer"}
     
    Exclude fields with type - String
    {"languagesKnown":[null,null,null]}

Именование пользовательских полей с использованием политики именования полей

Как мы видели в прошлой статье, Gson по умолчанию включает имя выходного поля json, такое же, как имя поля класса, а также мы можем переопределить это с помощью аннотации @serilizedName.

В Gson есть еще кое-что, что позволяет определить имя поля json, которое будет изменено на прописные, строчные и т. Д. Без использования каких-либо комментариев.

Для этого вам нужно использовать метод GsonBuilder (). SetFieldNamingPolicy () и передать соответствующий FieldNamePolicy.

Следующий листинг показывает использование:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package in.ajduke.ap013;
 
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
 
public class Example34 {
  public static void main(String[] args) {
     
    Gson gson = new Gson();
    String json = gson.toJson(new JsonClass());
    System.out.println("Default behaviour....");
    System.out.println(json);
     
    gson = new GsonBuilder().setFieldNamingPolicy(
    FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create();
    json = gson.toJson(new JsonClass());
    System.out.println("\nFields with lower case with dashes...");
    System.out.println(json);
     
    gson = new GsonBuilder().setFieldNamingPolicy(
    FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES).create();
    json = gson.toJson(new JsonClass());
    System.out.println("\nFields with upper case with spaces...");
    System.out.println(json);
     
  }
}
 
class JsonClass {
  String myField = "value1";
  String myAnotherField = "value2";
}
1
2
3
4
5
6
7
8
Default behaviour....
{"myField":"value1","myAnotherField":"value2"}
 
Fields with lower case and dashes...
{"my-field":"value1","my-another-field":"value2"}
 
Fields with lower case and dashes...
{"My Field":"value1","My Another Field":"value2"}