Jackson ObjectMapper

All lectures for GE purposes
1 уровень , 80 лекция
Открыта

Jackson – ეს არის პოპულარული ბიბლიოთეკა Java-ობიექტების სერიალიზაციისა/დესერიალიზაციისთვის სხვადასხვა ტექსტურ ფორმატებში. ძირითადი ფუნქციონალი JSON ფორმატთან სამუშაოდ არის კლასი ObjectMapper. სხვა ფორმატებთან მუშაობაში მისი მემკვიდრეები დაგეხმარებათ (XmlMapper, YAMLMapper). მემკვიდრეობის წყალობით, ყველა ფორმატთან მუშაობა მოხდება ერთნაირად, ერთი ინტერფეისით.

Jar-ფაილების გადმოწერა

სანამ მაგალითებს ვნახავთ, საჭიროა jar-ფაილების გადმოწერა Jackson-ისთვის და მათი პროექტში ჩართვა IntellijIDEA-ში. ვნახოთ, როგორ ვიძებნოთ საჭირო ფაილები jackson-databind მაგალითზე:

  1. გადადი ვებგვერდზე Maven Repository.

  2. ძიების ზოლში ჩააწერე “jackson-databind”, მიიღებ შედეგს:

  3. ჩვენთვის საინტერესოა პირველი ძიების შედეგი, გადადი ბმულზე.

  4. ზოგჯერ შეიძლება საჭირო იყოს კონკრეტული ვერსია ბიბლიოთეკის, რათა უზრუნველყოფოთ კომპონენტებთან თავსებადობა. შენთვის გამოდგება ბოლო ვერსია (ლექციის წერის დროს ეს არის 2.13.2.2), გადადი ბმულზე.

  5. გახსნილ გვერდზე გჭირდება ბმული "bundle":

  6. ჩამოვწერეთ jar-ფაილი ბმულზე.

ასევეა შესაძლებელი სხვა საჭირო jar-ფაილების მოძებნა და ჩამოტვირთვა:

ყველა საჭირო ფაილის გადმოწერის შემდეგ, ჩართე ისინი პროექტში IntellijIDEA-ში:

  1. გახსენი პროექტის პარამეტრები (შემიძლია ეს გავაკეთო კომბინაციით Ctrl+Alt+Shift+S).

  2. გადადი Libraries-ზე.

  3. დააჭირე +, შემდეგ Java, არჩიე ყველა გადმოწერილი ფაილი. უნდა გამოვიდეს შემდეგნაირად:

  4. ამით მზადებაა დასრულებული, ახლა ვცადოთ ObjectMapper საქმეში.

სერიალიზაცია JSON-ში

დავიწყოთ რომელიმე ობიექტის სერიალიზაციით 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 = "მოსახლე კუნტი";
    	book.author = "სტრუგაცკი ა., სტრუგაცკი ბ.";
    	book.pages = 413;

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

შედეგად main-ის გაშვების შემდეგ, მიიღებთ ასეთი შედეგი:

{"title":"მოსახლე კუნტი","author":"სტრუგაცკი ა., სტრუგაცკი ბ.","pages":413}

ObjectMapper-ს აქვს მრავალი დამატებითი პარამეტრი. გამოვიყენოთ ერთ-ერთი მათგანი, რათა JSON-სტრიქონი უფრო გამოსაკითხავად იყოს ფორმატირებული. ObjectMapper ობიექტის შექმნის შემდეგ ვასრულებთ ბრძანებას:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

ინფორმაცია შედეგში იგივე რჩება, მაგრამ დაემატება ფორმატირება და ხაზოვანი დაშლა:

{
  "title" : "მოსახლე კუნტი",
  "author" : "სტრუგაცკი ა., სტრუგაცკი ბ.",
  "pages" : 413
}

დესერიალიზაცია JSON-დან

ახლა შევასრულოთ საპირისპირო ქმედება: დესერიალიზაციის სტრიქონი ობიექტში. იმისთვის, რომ შევაფასოთ პროგრამის მუშაობა, Book კლასში დავამატოთ მეთოდი toString:


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

და შევასრულებთ ასეთ main:


public static void main(String[] args) throws Exception {
	String jsonString = "{\"title\":\"მოსახლე კუნტი\",\"author\":\"სტრუგაცკი ა., სტრუგაცკი ბ.\",\"pages\":413}";
	Book book = new ObjectMapper().readValue(jsonString, Book.class);
	System.out.println(book);
}

შედეგი:

Book{title='მოსახლე კუნტი', author='სტრუგაცკი ა., სტრუგაცკი ბ.', pages=413}

მეთოდი readValue გადატვირთულია, მას აქვს მრავალი ვარიანტი, რომელიც იღებს ფაილს, ბმულს, სხვადასხვა წაკითხვის ნაკადს და ა.შ. ჩვენი მაგალითის გამარტივებისთვის გამოიყენება ვარიანტი, რომელიც იღებს JSON-ს სტრიქონის სახით.

როგორც უკვე ვთქვით, ObjectMapper-ს აქვს მრავალი პარამეტრი, ზოგიერთ მათგანს განვიხილავ.

უცნობი თვისებების იგნორირება

განვიხილოთ სიტუაცია, როდესაც JSON-სტრიქონს აქვს თვისება, რომელიც Book კლასს არ აქვს:


public static void main(String[] args) throws Exception {
	String jsonString = """
        	{
          	"title" : "მოსახლე კუნტი",
          	"author" : "სტრუგაცკი ა., სტრუგაცკი ბ.",
          	"pages" : 413,
          	"unknown property" : 42
        	}""";
	ObjectMapper mapper = new ObjectMapper();
	Book book = mapper.readValue(jsonString, Book.class);
	System.out.println(book);
}

ამ კოდის შესრულების მცდელობაზე მივიღებთ 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);

ფუნქციონალურად ეს ჩანაწერი ანალოგიურია წინა ჩანაწერთან.

ახლა თუ გავუშვებთ main, დესერიალიზაცია წარმატებით ჩატარდება, ხოლო unknown property იგნორირებული იქნება.

მოსახერხებელი ანოტაციები

Jackson გვაწვდის რიგ ანოტაციებს სერიალიზაციის კასტომიზაციისთვის. განვიხილოთ რამდენიმე ყველაზე გამოსადეგი:

@JsonIgnore – გამოიყენება იმ ელემენტის ხაზზე, რომელიც უნდა იგნორირდეს სერიალიზაციის/დესერიალიზაციისას:


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

შედეგად, სერიალიზაციისას ველი author არ მოხვდება შედეგურ JSON-ში. დესერიალიზაციისას ველი author მიიღებს დეტექტურ მნიშვნელობას (null), მიუხედავად იმისა, რომ JSON-ში სხვა მნიშვნელობა იყო.

@JsonFormat – საშუალებას გვაძლევს დავადგინოთ სერიალიზებული მონაცემების ფორმატი. დავამატოთ Book კლასში კიდევ ერთი ველი Date ტიპის:


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

სერიალიზაციის შემდეგ მივიღებთ ასეთ JSON-ს:

 {
  "title" : "მოსახლე კუნტი",
  "author" : "სტრუგაცკი ა., სტრუგაცკი ბ.",
  "pages" : 413,
  "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" : "სტრუგაცკი ა., სტრუგაცკი ბ.",
  "pages" : 413,
  "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" : "სტრუგაცკი ა., სტრუგაცკი ბ.",
  "pages" : 413,
  "name" : "მოსახლე კუნტი",
  "quotedTitle" : "„მოსახლე კუნტი“"
}

@JsonInclude – ამ ანოტაციით შესაძლებელია ველისთვის იმის მითითება, როდის უნდა სერიალიზირდეს იგი. შეიძლება დაემატოს როგორც ცალკეულ ველებს, ისე მთელ კლასს. პირველად სცადოთ სერიალიზაცია არაინიციისებულ ველებით ობიექტზე:


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;
}

მაშინ მივიღებთ შედეგს:

{
  "pages" : 0
}

ახლა ველები, რომლებსაც აქვთ null მნიშვნელობა, არ სერიალიზირდნენ.

@JsonPropertyOrder – შესაძლებლობას გვაძლევს დავადგინოთ ველების სერიალიზაციის რიგი:


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

სერიალიზაციის შედეგი:

{
  "author" : "სტრუგაცკი ა., სტრუგაცკი ბ.",
  "title" : "მოსახლე კუნტი",
  "pages" : 413
}

ახლა შეგიძლია უბრალოდ დაიმახსოვრო, როგორ გამოიყენებს ანოტაციების გამოყენება, ამ მოდულის ბოლოს უფრო დეტალურად გაეცნობი მათ და შექმნი საკუთარ ანოტაციებს.

სერიალიზაცია და დესერიალიზაცია XML-ში

XML ფორმატში თუ უნდა სერიალიზაცია, შეგვიძლია გამოვიყენოთ ისევ იგივე პარამეტრები და ანოტაციები. ერთადერთი განსხვავება იქნება mapper ობიექტის რეალიზაცია:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "მოსახლე კუნტი";
	book.author = "სტრუგაცკი ა., სტრუგაცკი ბ.";
	book.pages = 413;
 
	ObjectMapper mapper = new XmlMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String xmlBook = mapper.writeValueAsString(book);
	System.out.println(xmlBook);
}

შედეგი:

 <Book>
  <title>მოსახლე კუნტი</title>
  <author>სტრუგაცკი ა., სტრუგაცკი ბ.</author>
  <pages>413</pages>
</Book>

დესერიალიზაცია XML-დან:


public static void main(String[] args) throws Exception {
   String xmlString = """
            <Book>
             <title>მოსახლე კუნტი</title>
             <author>სტრუგაცკი ა., სტრუგაცკი ბ.</author>
             <pages>413</pages>
           </Book>""";
   ObjectMapper mapper = new XmlMapper();
   Book book = mapper.readValue(xmlString, Book.class);
   System.out.println(book);
}

სერიალიზაცია და დესერიალიზაცია YAML-ში

ანალოგიურად XML, შეგვიძლია გამოვიყენოთ სწორად YAML-შიც:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "მოსახლე კუნტი";
	book.author = "სტრუგაცკი ა., სტრუგაცკი ბ.";
	book.pages = 413;
 
	ObjectMapper mapper = new YAMLMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String yamlBook = mapper.writeValueAsString(book);
	System.out.println(yamlBook);
}

შედეგი:

---
title: "მოსახლე კუნტი"
author: "სტრუგაცკი ა., სტრუგაცკი ბ."
pages: 413

დესერიალიზაცია YAML-დან:


public static void main(String[] args) throws Exception {
   String yamlString = """
           ---
           title: "მოსახლე კუნტი"
           author: "სტრუგაცკი ა., სტრუგაცკი ბ."
           pages: 413""";
   ObjectMapper mapper = new YAMLMapper();
   Book book = mapper.readValue(yamlString, Book.class);
   System.out.println(book);
}
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ