Шаг 143.
Язык программирования Java.
Библиотека Gson. Функции toJson и fromJson (окончание)

На этом шаге мы рассмотрим как сменить поведение сериализации и десериализации

Допустим у нас встала задача сериализовать и десериализовать коллекцию, которая содержит значения разных типов:

Collection collection = new ArrayList();
collection.add(1);
collection.add("2");
collection.add(true);
collection.add(new int[] {1,2,3});

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

  1. Использовать низкоуровневое API, рассмотренное нами ранее.
  2. Переопределить поведение сериализации и десериализации объектов (Gson это позволяет).

Рассмотрим второй способ (с первым способом вы сможете справиться самостоятельно). Пусть у нас есть следующий класс:

public class User {
    private String name;
    private Date birthDay;
    private char sex;

    public User(String name, Date birthDay, char sex) {
        this.name = name;
        this.birthDay = birthDay;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public Date getBirthDay() {
        return birthDay;
    }

    public char getSex() {
        return sex;
    }

    @Override
    public String toString() {
        return "name = " + name +
                ", birthDay = " + birthDay +
                ", sex = " + sex;
    }
}

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

public class UserJsonSerializerAndDeserializer
        implements JsonSerializer, JsonDeserializer {

    public static final String NAME_KEY = "name";
    public static final String BIRTH_DAY_KEY = "bd";
    public static final String SEX_KEY = "s";

    public JsonElement serialize(Object src,
                                 Type typeOfSrc,
                                 JsonSerializationContext context) {
        User user = (User) src;

        JsonObject jsonObject = new JsonObject();
        jsonObject.add(NAME_KEY, new JsonPrimitive(user.getName()));
        jsonObject.add(BIRTH_DAY_KEY, new JsonPrimitive(user.getBirthDay().getTime()));
        jsonObject.add(SEX_KEY, new JsonPrimitive(user.getSex() == 'M'));
        return jsonObject;
    }

    public Object deserialize(JsonElement json,
                              Type typeOfT,
                              JsonDeserializationContext context)
            throws JsonParseException {
        JsonObject jsonObject = (JsonObject) json;

        String name = jsonObject.get(NAME_KEY).toString();

        long milis = Integer.valueOf(jsonObject.get(BIRTH_DAY_KEY).toString());
        Date birthDay = new Date(milis);

        boolean isMen = Boolean.parseBoolean(jsonObject.get(SEX_KEY).toString());
        char sex = isMen ? 'M' : 'W';

        return new User(name, birthDay, sex);
    }
}

Поведение сериализации описано в функции serialize (функция интерфейса JsonSerializer), а десериализации - в функции deserialize (функция интерфейса JsonDeserializer). В теле этих функций мы используем уже знакомые нам класс низкоуровнего API JsonObject.

После того, как написан класс для смены поведения сериализации и десериализации, нужно указать объекту типа GsonBuilder, что будет такое поведение. Для этого нужно воспользоваться функцией registerTypeAdapter, как это показано ниже:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(User.class, new UserJsonSerializerAndDeserializer())
        .create();

User user = new User("Sergey", new Date(123), 'M');

String json = gson.toJson(user);
System.out.println(json);

user = gson.fromJson(json, User.class);
System.out.println(user);

// На экране
// {"name":"Sergey","bd":123,"s":true}
// name = "Sergey", birthDay = Thu Jan 01 05:00:00 YEKT 1970, sex = M

На следующем шаге мы рассмотрим класс JsonReader

Предыдущий шаг Содержание Следующий шаг