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, Linux, Hibernate, Collections, Stream API, многопоточность, файлы, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.