Статьи
YouTube-канал

Spring Boot: преобразование объекта в json

26 января 2020

Тэги: Java 10 json rest Spring Boot

Содержание

  1. Изменение имени поля
  2. Сортировка полей в алфавитном порядке
  3. Исключение пустых полей
  4. Произвольное количество полей
  5. Программное преобразование в json
  6. Заключение

Spring Boot значительно упрощает преобразование объекта в json. Предположим, у нас есть такой класс, содержащий какую-то информацию о пользователе:

public class User {
    private String firstName;
    private String lastName;
    private int age;

   // далее идут get- и set-методы для указанных полей...
}

Создадим контроллер, который будет его возвращать.

@RestController
public class JsonController {

    @GetMapping
    public User getUser() {
        var user = new User();
        user.setFirstName("Сигизмунд");
        user.setLastName("Петров");
        user.setAge(23);
        return user;
    }
}

Этих двух классов достаточно, чтобы вы уже могли получать информацию о пользователе в формате json! Выполнив GET-запрос к вашему приложению (по умолчанию http://127.0.0.1:8080/), вы получите такой json:

{
  "firstName": "Сигизмунд",
  "lastName": "Петров",
  "age": 23
}

То есть имена полей объекта мапятся один к одному в их представление в формате json.

Изменение имени поля

А что делать, если мы хотим поменять имя поля в json, не меняя при этом имя поля в java? Например, lastName переименовать в surname. На помощь нам придёт аннотация @JsonProperty, в качестве параметра мы указываем желаемое имя для данного поля.

public class User {

    private String firstName;
    @JsonProperty("surname")
    private String lastName;
    private int age;

В формате json наш объект будет выглядеть уже так:

{
  "firstName": "Сигизмунд",
  "age": 23,
  "surname": "Петров"
}

Сортировка полей в алфавитном порядке

В нашем примере у нас всего 3 поля и их порядок в формате json соответствует таковому в исходном классе. А если полей будет 33, то при тестировании будет сложно искать глазами нужное поле по его имени. Чтобы упростить поиск, давайте отсортируем имена полей в алфавитном порядке:

@JsonPropertyOrder(alphabetic = true)
public class User {

    private String firstName;
    @JsonProperty("surname")
    private String lastName;
    private int age;

Тогда json примет такой вид:

{
  "age": 23,
  "firstName": "Сигизмунд",
  "surname": "Петров"
}

Как видим, поля отсортировались в алфавитном порядке.

Исключение пустых полей

Теперь предположим, что значения для какого-то поля у нас нет. Например, фамилии:

@GetMapping
public User getUser() {
    var user = new User();
    user.setFirstName("Сигизмунд");
    user.setLastName(null);
    user.setAge(23);
    return user;
}

Тогда наш json будет выглядеть следующим образом:

{
  "age": 23,
  "firstName": "Сигизмунд",
  "surname": null
}

Что делать, если мы вообще не хотим отображать поля, для которых у нас нет значений? Мы можем либо явно исключить конкретное поле с помощью аннотации @JsonIgnore:

public class User {
    private String firstName;
    @JsonIgnore
    private String lastName;
    private int age;

Либо с помощью аннотации @JsonInclude на уровне всего класса указать, что в json попадают только поля с not-null значениями. Данный вариант предпочтительнее, поскольку задаёт единообразное поведение всех полей объекта.

@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
    private String firstName;
    private String lastName;
    private int age;

И в том, и в другом случае поле lastName будет исключено из json:

{
  "age": 23,
  "firstName": "Сигизмунд"
}

Произвольное количество полей

Если нам заранее не известно количество и типы полей, мы можем сложить их все в одну мапу, ключи которой при сериализации будут преобразованы в имена полей сущности, а значения мапы - в значения этой сущности. В этом нам поможет аннотация @JsonAnyGetter, которая вешается не на саму мапу, а на её get-метод.

public class User {

    private Map<String, Object> params = new TreeMap<>();

    @JsonAnyGetter
    public Map<String, Object> getParams() {
        return params;
    }
}

Тут мы используем TreeMap, ключи которой сортируются по алфавиту, т.к. аннотация @JsonPropertyOrder в данном случае не работает. Значения типизированы классом Object, чтобы в мапу можно было складывать объекты любых типов (и строки, и числа).

Заполнение полей может выглядеть так:

@GetMapping
public User getUser() {
    var user = new User();
    user.getParams().put("firstName", "Сигизмунд");
    user.getParams().put("surname", "Петров");
    user.getParams().put("age", 23);
    return user;
}

В результате мы получим уже знакомый нам формат json:

{
  "age": 23,
  "firstName": "Сигизмунд",
  "surname": "Петров"
}

Как видим, аннотация @JsonAnyGetter с одной стороны придаёт некоторую гибкость, но при этом не все рассмотренные выше аннотации с ней работают. В общем случае, если набор параметров фиксирован и заранее известен, лучше данный подход не использовать.

Программное преобразование в json

Кроме сериализации ответа на запрос, преобразование в json вы также можете выполнять в явном виде. Это бывает полезно, если json-представление объекта нужно записать в базу данных или в лог. Для этого нужно лишь внедрить в наш контроллер экземпляр класса ObjectMapper и использовать его метод writeValuesAsString().

@RestController
public class JsonController {

    private static final Logger log = LoggerFactory.getLogger(JsonController.class);
    private final ObjectMapper mapper;

    public JsonController(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    @GetMapping
    public User getUser() throws JsonProcessingException {
        var user = new User();
        user.setFirstName("Сигизмунд");
        user.setAge(23);
        log.info("Json: {}", mapper.writeValueAsString(user));
        return user;
    }
}

Обратите внимание, что у нас один конструктор в контроллере, поэтому аннотацию @Autowired перед конструктором мы можем опустить. Spring Boot видит зависимость от ObjectMapper и подгружает в контроллер его экземпляр. При выполнении запроса вы увидите json-представление класса User в логе приложения.

r.d.example.controller.JsonController    : Json: {"firstName":"Сигизмунд","age":23}

Заключение

Как видите, Spring Boot позволяет легко преобразовывать объекты в json, а также изменять дефолтное поведение сериализации при помощи аннотаций.


Облако тэгов

Kotlin, Java, Java 16, Java 11, Java 10, Java 9, Java 8, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, Hibernate, Collections, Stream API, многопоточность, ввод-вывод, Apache, maven, gradle, JUnit, YouTube, новости, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml

Последние статьи


Комментарии

Добавить комментарий

×

devmark.ru