Чтение и запись JSON на Котлине с Джексоном

В этой статье мы рассмотрим, как читать и записывать файлы JSON в Kotlin, в частности, с помощью библиотеки Джексона. Зависимость Джексона Чтобы использовать Джексон, мы хотим добавить в наш проект его зависимость jackson-module-kotlin. Если вы используете Maven, вы можете просто добавить:<dependency><groupId> com.fasterxml.jackson.module</groupId><artifactId> Джексон-модуль-Котлин</artifactId><version> 2.12.1</version></dependency> Или, если вы используете Gradle, вы можете добавить: implementationatio

В этой статье мы рассмотрим, как читать и записывать файлы JSON в Kotlin , в частности, с помощью библиотеки Джексона.

Джексонская зависимость

Чтобы использовать Jackson, мы хотим добавить в наш проект jackson-module-kotlin Если вы используете Maven, вы можете просто добавить:

 <dependency> 
 <groupId>com.fasterxml.jackson.module</groupId> 
 <artifactId>jackson-module-kotlin</artifactId> 
 <version>2.12.1</version> 
 </dependency> 

Или, если вы используете Gradle, вы можете добавить:

 implementation 'com.fasterxml.jackson.module:jackson-module-kotlin:2.12.1' 

Имея зависимость, давайте определим объект JSON, который мы хотим прочитать:

 { 
 "id":101, 
 "username":"admin", 
 "password":"Admin123", 
 "fullName":"Best Admin" 
 } 

Чтение объекта JSON в объект Kotlin

Давайте посмотрим, как мы можем десериализовать объект JSON в объект Kotlin. Поскольку мы хотим преобразовать содержимое JSON в объект Kotlin, давайте определим класс данных User

 data class User ( 
 val id: Int, 
 val username: String, 
 val password: String, 
 val fullName: String 
 ) 

Затем мы хотим создать экземпляр объекта сопоставления, что можно легко сделать с помощью:

 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 
 
 // Registering the Kotlin module with the ObjectMpper instance 
 val mapper = jacksonObjectMapper() 
 
 // JSON String 
 val jsonString = """{ 
 "id":101, 
 "username":"admin", 
 "password":"Admin123", 
 "fullName":"Best Admin" 
 }""" 

Сделав это, мы можем передать содержимое JSON в наши ObjectMapper методы, такие как readValue() , как обычно для Джексона:

 // Read data from a JSON string 
 val userFromJson = mapper.readValue<User>(jsonString) 
 // Or 
 val userFromJsonWithType: User = mapper.readValue(jsonString) 

Если мы напечатаем значение userFromJson мы увидим что-то вроде этого:

 User(id=101, username=admin, password=Admin123, fullName=Best Admin) 

readValue() можно использовать с Class или без него, как вы видели немного ранее с двумя переменными ( userFromJson и userFromJsonWithType ).

Примечание. Использование функции без Class материализует тип и автоматически создает TypeReference для Jackson.

Написание объекта JSON из объекта Kotlin

Теперь давайте посмотрим, как мы можем сериализовать объект Kotlin в объект JSON.

Мы будем использовать тот же класс данных ( User ) и немного поиграем с функциями Jackson:

 val user = User(102, "test", "pass12", "Test User") 
 val userJson = mapper.writeValueAsString(user) 
 println(userJson) 

Здесь мы создали новый экземпляр User с несколькими значениями.

Функция writeValueAsString() является нашим ключевым игроком здесь и сериализует любой объект и его поля в виде строки.

userFromJson переменную userFromJson и посмотрим, как она выглядит:

 { 
 "id":102, 
 "username":"test", 
 "password":"pass12", 
 "fullName":"Test User" 
 } 

Запись списка Kotlin в массив JSON

Часто мы имеем дело со списками и массивами, а не с отдельными объектами. Давайте посмотрим, как мы можем сериализовать список Kotlin в массив JSON .

Используя тот же класс данных, мы создадим список User и сериализуем их в массив JSON:

 val userList = mutableListOf<User>() 
 userList.add(User(102, "jsmith", " [email protected] ", "John Smith")) 
 userList.add(User(103, "janed", "Pass1", "Jane Doe")) 
 
 val jsonArray = mapper.writeValueAsString(userList) 
 println(jsonArray) 

Это приводит к:

 [ 
 { 
 "id":102, 
 "username":"jsmith", 
 "password":" [email protected] ", 
 "fullName":"John Smith" 
 }, 
 { 
 "id":103, 
 "username":"janed", 
 "password":"Pass1", 
 "fullName":"Jane Doe" 
 } 
 ] 

Чтение массива JSON в список Kotlin

Теперь давайте пойдем другим путем и десериализуем массив JSON в список Kotlin :

 val userListFromJson: List<User> = mapper.readValue(jsonArray) 
 println(userListFromJson) 

И это приводит к:

 [User(id=102, username=test, password=pass12, fullName=Test User), User(id=103, username=user, password=Pass1, fullName=Demo User)] 

Обработка двунаправленных отношений JSON

Еще одна распространенная вещь, с которой можно столкнуться, - это двунаправленные отношения. Во многих случаях вы можете захотеть установить отношения «один ко многим» или «многие к одному» между некоторыми объектами.

Для этого давайте создадим класс данных Author который может содержать один или несколько объектов типа Book а у Book может быть один Author :

 data class Author ( 
 val name: String, 
 val books: MutableList<Book> 
 ) 
 
 data class Book ( 
 val title: String, 
 val author: Author 
 ) 

Author содержит список, называемый books , типа Book . В то же время Book содержит экземпляр Author

Сделаем несколько экземпляров и попробуем их сериализовать:

 val author = Author("JK Rowling", mutableListOf()) 
 val bookOne = Book("Harry Potter 1", author) 
 val bookTwo = Book("Harry Potter 2", author) 
 author.books.add(bookOne) 
 author.books.add(bookTwo) 

Если бы мы сделали то же самое, что и раньше:

 val authors = mapper.writeValueAsString(author) 

Мы быстро столкнулись с проблемой:

 com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: Book["author"]->Author["books"]->... 

Author содержит Book , которая содержит Author , которая содержит Book , которая содержит Author , и так далее, пока не будет StackOverflowError .

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

 data class Author ( 
 val name: String, 
 @JsonManagedReference 
 val books: MutableList<Book> 
 ); 
 
 data class Book ( 
 val title: String, 
 @JsonBackReference 
 val author: Author 
 ); 

@JsonManagedReference указывает атрибут, который будет сериализован нормально, а @JsonBackReference будет указывать атрибут, опущенный при сериализации. Мы эффективно удалим ссылку author Book при сериализации каждого из них.

Теперь мы можем сериализовать авторов:

 val authors = mapper.writeValueAsString(author) 
 println(authors) 

Если мы запустим этот код, он выдаст:

 { 
 "name":"JK Rowling", 
 "books":[ 
 { 
 "title":"Harry Potter 1" 
 }, 
 { 
 "title":"Harry Potter 2" 
 } 
 ] 
 } 

Заключение

В этом руководстве мы рассмотрели, как читать и писать файлы JSON в Kotlin с помощью Jackson .

Мы рассмотрели необходимые зависимости, способы сериализации и десериализации объектов JSON и Kotlin, а также массивов и списков.

Наконец, мы рассмотрели, как обрабатывать двунаправленные отношения при сериализации и десериализации.

comments powered by Disqus