26 января 2020
Тэги: Java, json, rest, Spring Boot.
Spring Boot значительно упрощает преобразование объекта в json. Предположим, у нас есть такой класс, содержащий какую-то информацию о пользователе:
Создадим контроллер, который будет его возвращать.
Этих двух классов достаточно, чтобы вы уже могли получать информацию о пользователе в формате json! Выполнив GET-запрос к вашему приложению (по умолчанию http://127.0.0.1:8080/), вы получите такой json:
То есть имена полей объекта мапятся один к одному в их представление в формате json.
А что делать, если мы хотим поменять имя поля в json, не меняя при этом имя поля в java? Например, lastName переименовать в surname. На помощь нам придёт аннотация @JsonProperty, в качестве параметра мы указываем желаемое имя для данного поля.
В формате json наш объект будет выглядеть уже так:
В нашем примере у нас всего 3 поля и их порядок в формате json соответствует таковому в исходном классе. А если полей будет 33, то при тестировании будет сложно искать глазами нужное поле по его имени. Чтобы упростить поиск, давайте отсортируем имена полей в алфавитном порядке:
Тогда json примет такой вид:
Как видим, поля отсортировались в алфавитном порядке.
Теперь предположим, что значения для какого-то поля у нас нет. Например, фамилии:
Тогда наш json будет выглядеть следующим образом:
Что делать, если мы вообще не хотим отображать поля, для которых у нас нет значений? Мы можем либо явно исключить конкретное поле с помощью аннотации @JsonIgnore:
Либо с помощью аннотации @JsonInclude на уровне всего класса указать, что в json попадают только поля с not-null значениями. Данный вариант предпочтительнее, поскольку задаёт единообразное поведение всех полей объекта.
И в том, и в другом случае поле lastName будет исключено из json:
Если нам заранее не известно количество и типы полей, мы можем сложить их все в одну мапу, ключи которой при сериализации будут преобразованы в имена полей сущности, а значения мапы – в значения этой сущности. В этом нам поможет аннотация @JsonAnyGetter, которая вешается не на саму мапу, а на её get-метод.
Тут мы используем TreeMap, ключи которой сортируются по алфавиту, т.к. аннотация @JsonPropertyOrder в данном случае не работает. Значения типизированы классом Object, чтобы в мапу можно было складывать объекты любых типов (и строки, и числа).
Заполнение полей может выглядеть так:
В результате мы получим уже знакомый нам формат json:
Как видим, аннотация @JsonAnyGetter с одной стороны придаёт некоторую гибкость, но при этом не все рассмотренные выше аннотации с ней работают. В общем случае, если набор параметров фиксирован и заранее известен, лучше данный подход не использовать.
Кроме сериализации ответа на запрос, преобразование в json вы также можете выполнять в явном виде. Это бывает полезно, если json-представление объекта нужно записать в базу данных или в лог. Для этого нужно лишь внедрить в наш контроллер экземпляр класса ObjectMapper и использовать его метод writeValuesAsString().
Обратите внимание, что у нас один конструктор в контроллере, поэтому аннотацию @Autowired перед конструктором мы можем опустить. Spring Boot видит зависимость от ObjectMapper и подгружает в контроллер его экземпляр. При выполнении запроса вы увидите json-представление класса User в логе приложения.
Как видите, Spring Boot позволяет легко преобразовывать объекты в json, а также изменять дефолтное поведение сериализации при помощи аннотаций.
Kotlin, Java, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, H2, Linux, Hibernate, Collections, Stream API, многопоточность, чат-боты, нейросети, файлы, devops, Docker, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.