Jackson to popularna biblioteka służąca do serializacji/deserializacji obiektów Java do różnych formatów tekstowych. Główną funkcjonalnością do pracy z formatem JSON jest klasa ObjectMapper . A jego spadkobiercy ( XmlMapper , YAMLMapper ) pomogą pracować z innymi formatami. Dzięki dziedziczeniu praca ze wszystkimi formatami będzie odbywać się jednakowo, za pośrednictwem jednego interfejsu.
Pobierz pseudonimy słoików
Przed przestudiowaniem przykładów musisz pobrać słoiki Jacksona i połączyć je z projektem w IntellijIDEA. Przyjrzyjmy się, jak wyszukać potrzebne pliki na przykładzie jackson-databind :
-
Przejdź do witryny repozytorium Maven .
-
Wpisz „ jackson-databind ” w pasku wyszukiwania, otrzymasz wynik:
-
Interesuje nas pierwszy wynik wyszukiwania, kliknij link.
-
Czasami może być wymagana określona wersja biblioteki, aby zapewnić kompatybilność z innymi komponentami w projekcie. Najnowsza wersja będzie Ci odpowiadać (w momencie pisania wykładu jest to 2.13.2.2), kliknij link.
-
Na stronie, która się otworzy, potrzebujesz linku „pakietu”:
-
Pobierz plik jar z łącza .
Podobnie możesz znaleźć i pobrać pozostałe niezbędne słoiki:
Po pobraniu wszystkich niezbędnych plików podłącz je do projektu w IntellijIDEA:
-
Otwórz ustawienia projektu (można to zrobić za pomocą kombinacji Ctrl+Alt+Shift+S ).
-
Przejdź do Biblioteki .
-
Naciśnij + , następnie Java, wybierz wszystkie pobrane pliki. Powinno to wyglądać tak:
-
To kończy przygotowania, wypróbujemy ObjectMappera w akcji.
Serializacja do JSON
Najpierw serializuj jakiś obiekt do 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);
}
}
Kiedy uruchomisz main , otrzymasz to wyjście:
ObjectMapper ma wiele zaawansowanych opcji. Użyjmy jednego z nich, aby łańcuch JSON był czytelny i sformatowany. Po utworzeniu obiektuObiektMapperwykonajmy polecenie:
Informacje w danych wyjściowych pozostały takie same, ale dodano wcięcia i podziały wierszy:
„tytuł”: „Wyspa zamieszkana”,
„autor”: „Strugatsky A., Strugacki B.”,
„strony”: 413
}
Deserializacja z JSON
Teraz zróbmy coś przeciwnego: przekształcimy łańcuch znaków w obiekt. Aby móc ocenić działanie programu dodaj metodę toString do klasy Book :
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
", pages=" + pages +
'}';
}
I wykonaj to główne :
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);
}
Wniosek:
Metoda readValue jest przeciążona, ma wiele odmian, które akceptują plik, link, różne strumienie odczytu itp. Dla uproszczenia, w naszym przykładzie używamy wariantu, który akceptuje JSON jako napis.
Jak wspomniano powyżej, ObjectMapper ma wiele ustawień, spójrzmy na niektóre z nich.
Ignorowanie nieznanych właściwości
Rozważmy sytuację, w której łańcuch JSON ma właściwość, której nie ma w klasie 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);
}
Próbując wykonać ten kod, otrzymujemy UnrecognizedPropertyException . To zachowanie jest ustawione domyślnie, ale możemy je zmienić:
ObjectMapper mapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Podczas tworzenia obiektuObiektMapperużyj metody configure , aby ustawić żądane ustawienie na false . Metoda configure modyfikuje obiekt, do którego została wywołana, i zwraca ten sam obiekt, więc można ją wywołać w inny sposób:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Pod względem funkcjonalności ten wpis jest podobny do poprzedniego.
Jeśli teraz uruchomimy main , deserializacja powiedzie się, a nieznana właściwość zostanie zignorowana.
Wygodne adnotacje
Jackson zapewnia nam szereg adnotacji do wszechstronnego dostosowywania serializacji. Rzućmy okiem na niektóre z najbardziej przydatnych:
@JsonIgnore - umieszczony nad elementem, który ma być ignorowany podczas serializacji/deserializacji:
class Book {
public String title;
@JsonIgnore
public String author;
public int pages;
}
W rezultacie podczas serializacji polaautornie zostaną uwzględnione w wynikowym formacie JSON. Podczas deserializacji polaautorotrzyma wartość domyślną (null), nawet jeśli w JSON była inna wartość.
@JsonFormat - pozwala ustawić format serializowanych danych. Dodajmy jeszcze jedno pole Date do klasy Book :
class Book {
public String title;
public String author;
public int pages;
public Date createdDate = new Date();
}
Po serializacji otrzymujemy następujący JSON:
"title": "Zamieszkana wyspa",
"autor": "Strugatsky A., Strugatsky B.",
"pages": 413,
"createdDate": 1649330880788
}
Jak widać, data jest serializowana jako liczba. Dodaj adnotację i ustaw format:
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();
}
Teraz wynik serializacji:
"title" : "Wyspa zamieszkana",
"autor": "Strugatsky A., Strugatsky B.",
"pages" : 413,
"createdDate" : "2022-04-07"
}
@JsonProperty — umożliwia zmianę nazwy właściwości, do której zostanie serializowane pole. Możesz również oznaczyć metody tą adnotacją, a ich wartość zwrotna zostanie przekonwertowana na właściwość JSON podczas serializacji:
class Book {
@JsonProperty("name")
public String title;
public String author;
public int pages;
@JsonProperty("quotedTitle")
public String getQuotedTitle() {
return "\"" + title + "\"";
}
}
Wynik serializacji:
„autor”: „A. Strugacki, B. Strugacki”,
„strony”: 413,
„nazwa”: „Wyspa zamieszkana”,
„cytowany tytuł”: „Wyspa zamieszkana”
}
@JsonInclude - za pomocą tej adnotacji możesz określić w jakim przypadku pole powinno być serializowane. Możesz dodać zarówno pojedyncze pola, jak i całą klasę. Najpierw spróbujmy serializować obiekt z niezainicjowanymi polami:
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);
}
}
Wynik serializacji:
„tytuł”: zero,
„autor”: zero,
„strony”: 0
}
A jeśli dodasz adnotację:
@JsonInclude(JsonInclude.Include.NON_NULL)
class Book {
public String title;
public String author;
public int pages;
}
Następnie otrzymujemy wynik:
"strony" : 0
}
Teraz pola, które są puste , nie są serializowane.
@JsonPropertyOrder - pozwala ustawić kolejność serializacji dla pól:
@JsonPropertyOrder({"author", "title", "pages"})
class Book {
public String title;
public String author;
public int pages;
}
Wynik serializacji:
„autor”: „Strugatsky A., Strugacki B.”,
„tytuł”: „Wyspa zamieszkana”,
„strony”: 413
}
Na razie możesz po prostu zapamiętać, jak korzystać z adnotacji, a na końcu tego modułu poznamy je bardziej szczegółowo i stworzymy własne adnotacje.
Serializacja i deserializacja w XML
Jeśli potrzebujesz serializacji do formatu XML, możemy użyć tych samych ustawień i adnotacji. Jedyną różnicą będzie implementacja obiektuodwzorowujący:
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);
}
Wniosek:
<title>Zamieszkana wyspa</title>
<author>Strugatsky A., Strugacki B.</author>
<pages>413</pages>
</Book>
Deserializacja 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);
}
Serializacja i deserializacja w YAML
Podobnie postępujemy z XML z YAML:
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);
}
Wniosek:
tytuł: "Zamieszkana wyspa"
autor: "Strugatsky A., Strugacki B."
strony: 413
Deserializacja 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);
}