Холодной весенней ночью я наконец-таки перешел на 33 уровень. Потирая свои программистские ручки, я уже готовился объять всю сферу сериализации, десериализации JSON, но, к сожалению, ничего не понял. Текст лекции не запомнился, а задачи решались как-то интуитивно. В связи с этим решил полезть в дебри Jackson Framework и разобраться, что же такое этот JSON.
Jackson Framework
Все свои познания постараюсь изложить практико-ориентированно и лаконично в формате шпаргалки (как для себя, так и для читателей). Путешествие в Jackson Annotations. Первое, что мы встречаем на пути в JSON — это аннотация @JsonAutoDetect. На первый взгляд легкая аннотация, но с ней автору пришлось разбираться дольше всего. Аннотация имеет 5 нужных нам методов:
  • fieldVisibility() - сериализует поля только с указанным модификатором доступа
  • getterVisibility()/setterVisibility() - сериализует поля, у которых геттер/сеттер имеет указанный модификатор доступа
  • isGetterVisibility() - отдельная реализация для булевских геттеров
Важно понимать, что методы работают дизъюнктивно. Т.е. если поле соответствует хотя бы одному из указанных в аннотации параметров, то оно попадет в JSON. Попытайтесь ответить, что выведет данный код, если мы создадим экземляр, используя конструктор без параметров:
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY,
        getterVisibility        = JsonAutoDetect.Visibility.PUBLIC_ONLY,
        setterVisibility        = JsonAutoDetect.Visibility.PUBLIC_ONLY,
        isGetterVisibility      = JsonAutoDetect.Visibility.PROTECTED_AND_PUBLIC)
public class HeadClass {
    public String name;
    private Map<String, String> properties;
    public Queue<String> queue;
    protected List<String> list;
    private int age;
    private int number;
    private boolean isHead;

    protected HeadClass(int age) {
        this.age = age;
    }

    public HeadClass() {}

    Map<String, String> getProperties() {
        return properties;
    }

    protected boolean isHead() {
        return isHead;
    }

    protected void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}
А если убрать isGetterVisibility? Четыре перечисленных метода конфигурировали процесс сериализации. Пятый же в свою очередь регулирует процесс десериализации:
  • creatorVisibility() - самый сложный метод для понимания. Он работает с конструкторами и с фабричными методами (методы, которые создают объект при обращении к ним). Рассмотрим пример:
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.PROTECTED_AND_PUBLIC)
public class HeadClass {
    public String name;
    public int id;

    HeadClass(@JsonProperty(value = "name") String name, @JsonProperty(value = "id") int id) {
        this.name = name;
        this.id = id;
    }

    protected HeadClass(String name) {
        this.name = name;
        this.id = 123;
    }

    protected HeadClass(int id) {
        this.id = id;
        this.name = "Yes!";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    String forDeserialize = "{\"name\":\"No!\",\"id\":123}";
    StringReader reader = new StringReader(forDeserialize);

    HeadClass headClass1 = (HeadClass) mapper.readValue(reader, HeadClass.class);
}
Важное замечание по механизму десериализации! Когда мы пытаемся создать объект из JSON, то будет осуществляться поиск конструктора требуемого класса с таким же набором параметров, что и в JSON объекте. В примере выше наш JSON объект состоит из двух параметров: name, id. Угадайте, к какому конструктору он обратится. И да, если мы скомпилируем этот код, он выдаст ошибку, а почему? Потому что мы ограничили видимость конструктора (видны только конструкторы с модификатором protected, public). Если вы удалите creatorVisibility, то он заработает. Возникает вопрос. А что за @JsonProperty в конструкторе. Об этом думаю рассказать в следующей части статьи. P.S. Господа, очень бы хотелось получить хоть какой-то отклик о статье. Интересно, пользуется ли спросом эта тема и стоит ли продолжать, потому что тем очень много и все они очень интересные. Хотелось бы еще рассмотреть такие аннотации, как @JsonView, @JsonManagedReference, @JsonBackReference, @JsonUnwrapped и т.д. Спасибо :)