Jackson е популярна библиотека за сериализиране/десериализиране на Java обекти в различни текстови формати. Класът ObjectMapper е основният начин на библиотеката да работи с JSON формата. За други формати имаме негови наследници ( XmlMapper , YAMLMapper ). Благодарение на наследяването можем да работим с всички формати по последователен начин, чрез един интерфейс.

Изтегляне на jar файлове

Преди да изучаваме примерите, трябва да изтеглим Jackson jar файлове и да ги свържем с проекта в IntelliJ IDEA. Нека вземем примера на jackson-databind , за да видим How да търсим необходимите файлове:

  1. Отидете на уебсайта на Maven Repository .

  2. Въведете " jackson-databind " в полето за търсене. Ще получите следното:

  3. Първият резултат от търсенето е това, което ни интересува. Следвайте връзката.

  4. Понякога може да е необходима определена version на библиотека, за да се осигури съвместимост с други компоненти в даден проект. Най-новата version трябва да работи (по време на писане на този урок тя е 2.13.2.2). Следвайте връзката.

  5. На pageта, която се отваря, искате връзката „пакет“:

  6. Изтеглете jar file, като използвате тази връзка .

Следвайки подобна proceduresа, можете да намерите и изтеглите останалите необходими jar файлове:

След като изтеглите всички необходими файлове, свържете ги към проекта в IntelliJ IDEA:

  1. Отворете настройките на проекта (можете да го направите с клавишната комбинация Ctrl+Alt+Shift+S ).

  2. Отидете на Библиотеки .

  3. Натиснете + и след това "Java". Изберете всички изтеглени файлове. Ето Howво трябва да получим:

  4. Това приключва нашата подготвителна работа. Сега можем да изпробваме ObjectMapper в действие.

Сериализация в JSON

Първо, нека сериализираме няHowъв обект в JSON:


import com.fasterxml.jackson.databind.ObjectMapper;
 
class Book {
	public String title;
	public String author;
	public int pages;
}
 
public class Solution {
	public static void main(String[] args) throws Exception {
    	Book book = new Book();
    	book.title = "Good Omens";
    	book.author = "Pratchett T., Gaiman N.";
    	book.pages = 383;
 
    	ObjectMapper mapper = new ObjectMapper();
    	String jsonBook = mapper.writeValueAsString(book);
    	System.out.println(jsonBook);
	}
}

Стартирането на main ще ви даде този резултат:

{"title":"Добри поличби","author":"Пратчет Т., Гейман Н.","страници":383}

ObjectMapper има много разширени настройки . Нека използваме един от тях, за да направим JSON низа по-четлив. След създаването наObjectMapperобект, изпълнете този оператор:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

Информацията в изхода остава същата, но сега има отстъпи и прекъсвания на редове:

{
  "title" : "Добри поличби",
  "author" : "Пратчет Т., Гейман Н.",
 "страници" : 383
}

Десериализация от JSON

Сега нека направим обратното действие: ще десериализираме низ в обект. За да можете да видите Howво прави програмата, нека заменим метода toString в класа Book :


@Override
public String toString() {
	return "Book{" +
        	"title='" + title + '\'' +
        	", author='" + author + '\'' +
        	", pages=" + pages +
        	'}';
}

И ще направим следното в основния метод:


public static void main(String[] args) throws Exception {
	String jsonString = "{\"title\":\"Good Omens\",\"author\":\"Pratchett T., Gaiman N.\",\"pages\":383}";
	Book book = new ObjectMapper().readValue(jsonString, Book.class);
	System.out.println(book);
}

Изход:

Книга{title='Good Omens', author='Pratchett T., Gaiman N.', pages=383}

Методът readValue е претоварен — има много варианти, които приемат файл, връзка, различни входни потоци и т.н. За простота нашият пример използва вариант, който приема JSON низ.

Както бе споменато по-горе, ObjectMapper има много настройки. Нека да разгледаме няколко от тях.

Игнориране на неизвестни свойства

Помислете за ситуация, при която JSON низ има свойство, което не съществува в класа Book :


public static void main(String[] args) throws Exception {
	String jsonString = """
        	{
          	"title" : "Good Omens",
          	"author" : "Pratchett T., Gaiman N.",
          	"pages" : 383,
          	"unknown property" : 42
        	}""";
	ObjectMapper mapper = new ObjectMapper();
	Book book = mapper.readValue(jsonString, Book.class);
	System.out.println(book);
}

Изпълнението на този code ни дава UnrecognizedPropertyException . Това е поведението по подразбиране, но можем да го променим:


ObjectMapper mapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

При създаване наObjectMapperобект, използваме метода configure , за да зададем съответната настройка на false . Методът configure модифицира обекта, към който е извикан, и след това връща същия обект, така че можем да направим това извикване по различен начин:


ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

По отношение на функционалността тази нотация е точно като предишната.

Ако сега стартираме основния метод, десериализацията ще успее и неизвестното свойство ще бъде игнорирано.

Удобни анотации

Джаксън ни предоставя няколко анотации, които ни позволяват да персонализираме процеса на сериализация по всяHowви начини. Нека да разгледаме някои от най-полезните:

@JsonIgnore — Тази анотация се поставя над елемент, който трябва да се игнорира по време на сериализация/десериализация:


class Book {
	public String title;
	@JsonIgnore
	public String author;
	public int pages;
}

Тукавторполето няма да бъде включено в получения JSON по време на сериализация. При десериализация,авторще получи стойността по подразбиране (null), дори ако JSON има различна стойност.

@JsonFormat — Тази анотация ви позволява да зададете формата на сериализираните данни. Нека добавим още едно поле, Date , към класа Book :


class Book {
	public String title;
	public String author;
	public int pages;
	public Date createdDate = new Date();
}

След сериализиране получаваме следния JSON:

 {
  "title" : "Добри поличби",
  "author" : "Пратчет Т., Гейман Н.",
  "страници" : 383,
  "createdDate" : 1649330880788
}

Както можете да видите, датата е сериализирана като число. Ще добавим анотация и ще зададем формата:


class Book {
	public String title;
	public String author;
	public int pages;
	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
	public Date createdDate = new Date();
}

Сега резултатът от сериализацията е:

{
  "title" : "Добри поличби",
  "author" : "Пратчет Т., Гейман Н.",
  "страници" : 383,
  "createdDate" : "2022-04-07"
}

@JsonProperty — Тази анотация ви позволява да промените името на свойството, представляващо сериализираното поле. Можете също да маркирате методи с тази анотация. Ако го направите, тогава тяхната върната стойност ще бъде преобразувана в свойство JSON по време на сериализация:


class Book {
	@JsonProperty("name")
	public String title;
	public String author;
	public int pages;
 
	@JsonProperty("quotedTitle")
	public String getQuotedTitle() {
    	    return "\"" + title + "\"";
	}
}

Резултат от серализацията:

{
  "author" : "Пратчет Т., Гейман Н.",
  "страници" : 383,
  "name" : "Добри поличби",
  "quotedTitle" : "\"Добри поличби\""
}

@JsonInclude — Използвайки тази анотация, можете да посочите условия, които трябва да бъдат изпълнени, за да бъде сериализирано поле. Можете да го приложите към отделни полета or цял клас. Първо, нека се опитаме да сериализираме обект с неинициализирани полета:


public class Solution {
	public static void main(String[] args) throws Exception {
    		Book book = new Book();

    		ObjectMapper mapper = new ObjectMapper();
    		mapper.enable(SerializationFeature.INDENT_OUTPUT);
    		String jsonBook = mapper.writeValueAsString(book);
    		System.out.println(jsonBook);
	}
}

Резултат от серализацията:

{
  "title" : null,
  "author" : null,
  "pages" : 0
}

И ако добавите анотацията:


@JsonInclude(JsonInclude.Include.NON_NULL)
class Book {
	public String title;
	public String author;
	public int pages;
}

Тогава получаваме този резултат:

{
  "страници": 0
}

Сега полетата, които са нулеви , не се сериализират.

@JsonPropertyOrder — Тази анотация ви позволява да зададете реда, в който полетата се сериализират:


@JsonPropertyOrder({"author", "title", "pages"})
class Book {
	public String title;
	public String author;
	public int pages;
}

Резултат от серализацията:

{
  "author" : "Пратчет Т., Гейман Н.",
  "title" : "Добри поличби",
  "страници" : 383
}

Засега просто запомнете How да използвате анотации. В края на този модул ще ги опознаем по-добре и дори ще създадем свои собствени анотации.

Сериализация и десериализация в XML

Ако трябва да сериализираме в XML, можем да използваме всички същите настройки и анотации. Единствената разлика ще бъде изпълнението накартографски обект:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Good Omens";
	book.author = "Pratchett T., Gaiman N.";
	book.pages = 383;
 
	ObjectMapper mapper = new XmlMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String xmlBook = mapper.writeValueAsString(book);
	System.out.println(xmlBook);
}

Изход:

 <Book>
  <title>Добри поличби</title>
  <author>Пратчет Т., Гейман Н.</author>
  <pages>383</pages>
</Book>

Десериализация на XML:


public static void main(String[] args) throws Exception {
   String xmlString = """
            <Book>
             <title>Good Omens</title>
             <author>Pratchett T., Gaiman N.</author>
             <pages>383</pages>
           </Book>""";
   ObjectMapper mapper = new XmlMapper();
   Book book = mapper.readValue(xmlString, Book.class);
   System.out.println(book);
}

Сериализация и десериализация в YAML

Ние обработваме YAML по същия начин, Howто обработваме XML:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Good Omens";
	book.author = "Pratchett T., Gaiman N.";
	book.pages = 383;
 
	ObjectMapper mapper = new YAMLMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String yamlBook = mapper.writeValueAsString(book);
	System.out.println(yamlBook);
}

Изход:

---
заглавие: "Добри поличби"
автор: "Пратчет Т., Геймън Н."
страници: 383

Десериализация на YAML:


public static void main(String[] args) throws Exception {
   String yamlString = """
           ---
           title: "Good Omens"
           author: "Pratchett T., Gaiman N."
           pages: 383""";
   ObjectMapper mapper = new YAMLMapper();
   Book book = mapper.readValue(yamlString, Book.class);
   System.out.println(book);
}