खोज…


परिचय

जावा एक तंत्र प्रदान करता है, जिसे ऑब्जेक्ट सीरीज़ेशन कहा जाता है, जहाँ किसी ऑब्जेक्ट को बाइट्स के अनुक्रम के रूप में दर्शाया जा सकता है, जिसमें ऑब्जेक्ट के डेटा के साथ-साथ ऑब्जेक्ट के प्रकार और ऑब्जेक्ट में संग्रहीत डेटा के प्रकार के बारे में जानकारी शामिल होती है।

किसी सीरियल किए गए ऑब्जेक्ट को किसी फ़ाइल में लिखे जाने के बाद, इसे फ़ाइल से पढ़ा जा सकता है और deserialized किया जा सकता है, जो कि प्रकार की जानकारी और बाइट्स ऑब्जेक्ट का प्रतिनिधित्व करता है और इसके डेटा का उपयोग मेमोरी में ऑब्जेक्ट को फिर से बनाने के लिए किया जा सकता है।

जावा में मूल सीरियल

Serialization क्या है

सीरियलाइज़ेशन किसी वस्तु की अवस्था (उसके संदर्भों सहित) को बाइट्स के अनुक्रम में परिवर्तित करने की प्रक्रिया है, साथ ही उन बाइट्स को कुछ भविष्य के समय में एक जीवित वस्तु में पुनर्निर्माण करने की प्रक्रिया है। जब आप ऑब्जेक्ट को जारी रखना चाहते हैं तो सीरियललाइज़ेशन का उपयोग किया जाता है। यह जावा आरएमआई द्वारा जेवीएम के बीच वस्तुओं को पारित करने के लिए भी उपयोग किया जाता है, या तो किसी ग्राहक से सर्वर तक एक विधि मंगलाचरण में तर्क के रूप में या विधि आह्वान से मूल्यों को वापस करने के रूप में, या दूरस्थ तरीकों से फेंके गए अपवाद के रूप में। सामान्य तौर पर, क्रमांकन का उपयोग तब किया जाता है जब हम चाहते हैं कि वस्तु जेवीएम के जीवनकाल से परे मौजूद है।

java.io.Serializable एक मार्कर इंटरफ़ेस है (जिसका कोई शरीर नहीं है)। इसका उपयोग केवल जावा कक्षाओं को क्रमिक रूप में "चिह्नित" करने के लिए किया जाता है।

प्रत्येक serializable वर्ग एक संस्करण संख्या, एक कहा जाता है के साथ क्रमांकन क्रम सहयोगियों serialVersionUID , जो डी -serialization दौरान प्रयोग किया जाता है की पुष्टि है कि प्रेषक और एक धारावाहिक वस्तु के रिसीवर कि उद्देश्य यह है कि क्रमबद्धता के लिए सम्मान के साथ संगत कर रहे हैं के लिए भरी हुई श्रेणियां होती हैं। यदि रिसीवर ने ऑब्जेक्ट के लिए एक वर्ग लोड किया है, जिसमें संबंधित प्रेषक वर्ग की तुलना में एक अलग serialVersionUID है, तो deserialization के परिणामस्वरूप InvalidClassException । एक serializable वर्ग का अपना घोषणा कर सकते हैं serialVersionUID नाम के एक क्षेत्र की घोषणा के द्वारा स्पष्ट रूप से serialVersionUID कि होना चाहिए static, final, और प्रकार के long :

ANY-ACCESS-MODIFIER static final long serialVersionUID = 1L;

क्रमबद्धता के लिए एक वर्ग को योग्य कैसे बनाया जाए

किसी ऑब्जेक्ट को जारी रखने के लिए संबंधित वर्ग को java.io.Serializable इंटरफ़ेस लागू करना होगा।

import java.io.Serializable;

public class SerialClass implements Serializable {

    private static final long serialVersionUID = 1L;  
    private Date currentTime;
    
    public SerialClass() {
        currentTime = Calendar.getInstance().getTime();
    }

    public Date getCurrentTime() {
        return currentTime;
    }
}

किसी फ़ाइल में ऑब्जेक्ट कैसे लिखें

अब हमें इस ऑब्जेक्ट को एक फ़ाइल सिस्टम पर लिखना होगा। हम इस उद्देश्य के लिए java.io.ObjectOutputStream उपयोग करते हैं।

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;

public class PersistSerialClass {

    public static void main(String [] args) {
        String filename = "time.ser";            
        SerialClass time = new SerialClass(); //We will write this object to file system.
        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
            out.writeObject(time); //Write byte stream to file system.
            out.close();
        } catch(IOException ex){
            ex.printStackTrace();
        }
     }
 }

किसी वस्तु को उसकी क्रमबद्ध स्थिति से कैसे पुनः निर्मित किया जाए

संग्रहीत वस्तु को बाद में java.io.ObjectInputStream का उपयोग करके फ़ाइल सिस्टम से पढ़ा जा सकता है जैसा कि नीचे दिखाया गया है:

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.java.lang.ClassNotFoundException;

 public class ReadSerialClass {

    public static void main(String [] args) {
        String filename = "time.ser";    
        SerialClass time = null;

        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
            time = (SerialClass)in.readObject();
            in.close();
        } catch(IOException ex){
            ex.printStackTrace();
        } catch(ClassNotFoundException cnfe){
            cnfe.printStackTrace();
        }
        // print out restored time
        System.out.println("Restored time: " + time.getTime());
     }
 }

क्रमबद्ध वर्ग द्विआधारी रूप में है। यदि वर्ग परिभाषा में परिवर्तन होता है तो deserialization समस्याग्रस्त हो सकता है: विवरण के लिए जावा Serialization विनिर्देशन के क्रमबद्ध ऑब्जेक्ट्स अध्याय का संस्करण देखें।

किसी ऑब्जेक्ट को सीरियल करना पूरे ऑब्जेक्ट ग्राफ को क्रमबद्ध करता है जिसमें यह मूल है, और चक्रीय ग्राफ की उपस्थिति में सही ढंग से संचालित होता है। ऑब्जेक्ट ObjectOutputStream करने के लिए ऑब्जेक्ट को reset() एक reset() विधि प्रदान की जाती है जो पहले से ही धारावाहिक रूप से ObjectOutputStream हो चुकी है।

क्षणिक-क्षेत्र - सीरियल

Gson के साथ सीरियल

Gson के साथ सरलीकरण आसान है और JSON को सही आउटपुट देगा।

public class Employe {

    private String firstName;
    private String lastName;
    private int age;      
    private BigDecimal salary;
    private List<String> skills;

    //getters and setters
}

(क्रमबद्धता)

//Skills 
List<String> skills = new LinkedList<String>();
skills.add("leadership");
skills.add("Java Experience");

//Employe
Employe obj = new Employe();
obj.setFirstName("Christian");
obj.setLastName("Lusardi");
obj.setAge(25);
obj.setSalary(new BigDecimal("10000"));
obj.setSkills(skills);

//Serialization process
Gson gson = new Gson();
String json = gson.toJson(obj); //{"firstName":"Christian","lastName":"Lusardi","age":25,"salary":10000,"skills":["leadership","Java Experience"]}

ध्यान दें कि आप वस्तुओं को गोलाकार संदर्भों के साथ अनुक्रमित नहीं कर सकते हैं क्योंकि इससे अनंत पुनरावृत्ति होगी।

(Deserialization)

//it's very simple...
//Assuming that json is the previous String object....

Employe obj2 = gson.fromJson(json, Employe.class); // obj2 is just like obj

जैक्सन 2 के साथ सीरियल

निम्नलिखित एक कार्यान्वयन है जो दर्शाता है कि किसी वस्तु को उसके JSON स्ट्रिंग में कैसे क्रमांकित किया जा सकता है।

class Test {

    private int idx;
    private String name;

    public int getIdx() {
        return idx;
    }

    public void setIdx(int idx) {
        this.idx = idx;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

क्रमबद्धता:

Test test = new Test();
test.setIdx(1);
test.setName("abc");
    
ObjectMapper mapper = new ObjectMapper();

String jsonString;
try {
    jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(test);
    System.out.println(jsonString);
} catch (JsonProcessingException ex) {
    // Handle Exception
}

आउटपुट:

{
  "idx" : 1,
  "name" : "abc"
}

यदि आपको इसकी आवश्यकता नहीं है, तो आप डिफ़ॉल्ट सुंदर प्रिंटर को छोड़ सकते हैं।

यहाँ उपयोग की जाने वाली निर्भरता इस प्रकार है:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.6.3</version>
</dependency>

कस्टम सीरियल

इस उदाहरण में हम एक ऐसा वर्ग बनाना चाहते हैं जो कंसोल को उत्पन्न और आउटपुट करेगा, दो पूर्णांकों की सीमा के बीच एक यादृच्छिक संख्या जो कि आरंभीकरण के दौरान तर्क के रूप में पारित हो जाती है।

    public class SimpleRangeRandom implements Runnable {
    private int min;
    private int max;

    private Thread thread;

    public SimpleRangeRandom(int min, int max){
        this.min = min;
        this.max = max;
        thread = new Thread(this);
        thread.start();
    }

    @Override
 private void WriteObject(ObjectOutputStreamout) throws IO Exception;
    private void ReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
    public void run() {
        while(true) {
            Random rand = new Random();
            System.out.println("Thread: " + thread.getId() + " Random:" + rand.nextInt(max - min));
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    }

अब अगर हम इस वर्ग को धारावाहिक बनाना चाहते हैं तो कुछ समस्याएं होंगी। थ्रेड कुछ निश्चित सिस्टम-स्तरीय कक्षाओं में से एक है जो कि धारावाहिक नहीं हैं। इसलिए हमें धागे को क्षणिक घोषित करने की आवश्यकता है। ऐसा करने से हम इस वर्ग की वस्तुओं को क्रमबद्ध कर पाएंगे लेकिन फिर भी हमारे पास एक मुद्दा होगा। जैसा कि आप कंस्ट्रक्टर में देख सकते हैं कि हमने अपने रैंडमाइज़र का न्यूनतम और अधिकतम मान निर्धारित किया है और इसके बाद हम उस थ्रेड को शुरू करते हैं जो रैंडम वैल्यू बनाने और प्रिंट करने के लिए जिम्मेदार है। इस प्रकार जब रीडऑब्जेक्ट () को कॉल करके बनी हुई ऑब्जेक्ट को रिस्टोर किया जाता है , तो कंस्ट्रक्टर फिर से नहीं चलेगा क्योंकि नई ऑब्जेक्ट का कोई निर्माण नहीं है। उस मामले में हमें कक्षा के अंदर दो तरीके प्रदान करके एक कस्टम सीरियल बनाने की आवश्यकता है। वे विधियाँ हैं:

private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

इस प्रकार readObject में हमारे कार्यान्वयन को जोड़कर () हम अपना सूत्र आरंभ और शुरू कर सकते हैं:

class RangeRandom implements Serializable, Runnable {

private int min;
private int max;

private transient Thread thread;
//transient should be any field that either cannot be serialized e.g Thread or any field you do not want serialized

public RangeRandom(int min, int max){
    this.min = min;
    this.max = max;
    thread = new Thread(this);
    thread.start();
}

@Override
public void run() {
    while(true) {
        Random rand = new Random();
        System.out.println("Thread: " + thread.getId() + " Random:" + rand.nextInt(max - min));
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    thread = new Thread(this);
    thread.start();
}
}

यहाँ हमारे उदाहरण के लिए मुख्य है:

public class Main {
public static void main(String[] args) {
    System.out.println("Hello");
    RangeRandom rangeRandom = new RangeRandom(1,10);

    FileOutputStream fos = null;
    ObjectOutputStream out = null;
    try
    {
        fos = new FileOutputStream("test");
        out = new ObjectOutputStream(fos);
        out.writeObject(rangeRandom);
        out.close();
    }
    catch(IOException ex)
    {
        ex.printStackTrace();
    }


    RangeRandom rangeRandom2 = null;
       FileInputStream fis = null;
       ObjectInputStream in = null;
       try
       {
             fis = new FileInputStream("test");
             in = new ObjectInputStream(fis);
           rangeRandom2 = (RangeRandom)in.readObject();
             in.close();
           }
       catch(IOException ex)
       {
             ex.printStackTrace();
           }
       catch(ClassNotFoundException ex)
       {
             ex.printStackTrace();
           }

}
}

यदि आप मुख्य चलाते हैं तो आप देखेंगे कि प्रत्येक RangeRandom उदाहरण के लिए दो थ्रेड चल रहे हैं और ऐसा इसलिए है क्योंकि थ्रेड.स्टार्ट () विधि अब कंस्ट्रक्टर और रीडऑबजेक्ट () दोनों में है।

संस्करण और serialVersionUID

आप को लागू जब java.io.Serializable इंटरफ़ेस एक वर्ग serializable बनाने के लिए, एक के लिए संकलक दिखता static final क्षेत्र नामित serialVersionUID प्रकार के long । यदि वर्ग के पास इस क्षेत्र को स्पष्ट रूप से घोषित नहीं किया गया है, तो संकलक एक ऐसा क्षेत्र बनाएगा और इसे एक मान के साथ असाइन करेगा जो कि serialVersionUID कार्यान्वयन पर निर्भर गणना से बाहर आता है। यह संगणना वर्ग के विभिन्न पहलुओं पर निर्भर करता है और यह सूर्य द्वारा दी गई वस्तु क्रमांकन विनिर्देशों का अनुसरण करता है। लेकिन, मूल्य सभी संकलक कार्यान्वयनों में समान होने की गारंटी नहीं है।

इस मान का उपयोग क्रमांकन के संबंध में कक्षाओं की अनुकूलता की जाँच के लिए किया जाता है और यह किसी सहेजे गए ऑब्जेक्ट को क्रमबद्ध करते समय किया जाता है। सीरियलाइज़ेशन रनटाइम यह पुष्टि करता है कि serialVersionUID - serialVersionUID को डी- serialVersionUID डेटा से पढ़ा जाता है और क्लास में घोषित किए गए serialVersionUID बिल्कुल समान हैं। अगर ऐसा नहीं है, तो यह एक InvalidClassException फेंकता है।

यह अत्यधिक अनुशंसा की जाती है कि आप स्पष्ट रूप से अपने सभी वर्गों में लंबे और नामित 'क्रमबद्धता' नाम के स्थिर, अंतिम क्षेत्र की घोषणा करें और आरंभ करें, यदि आप नहीं जा रहे हैं, तो इस क्षेत्र के लिए मान की डिफ़ॉल्ट गणना पर निर्भर होने के बजाय आप इसे सीरियल बनाने योग्य बनाना चाहते हैं। संस्करण का उपयोग करें। 'serialVersionUID' अभिकलन अत्यंत संवेदनशील है और एक संकलक कार्यान्वयन से दूसरे में भिन्न हो सकता है और इसलिए आप InvalidClassException को एक ही वर्ग के लिए भी प्राप्त कर सकते हैं, क्योंकि आपने प्रेषक पर विभिन्न संकलक कार्यान्वयन का उपयोग किया था और क्रमबद्धता प्रक्रिया के रिसीवर के छोर।

public class Example implements Serializable {          
    static final long serialVersionUID = 1L /*or some other value*/;
    //...
}

जब तक serialVersionUID समान है, तब तक Java Serialization एक वर्ग के विभिन्न संस्करणों को संभाल सकता है। संगत और असंगत परिवर्तन हैं;

संगत परिवर्तन

  • फ़ील्ड जोड़ना: जब पुनर्गठित किए जा रहे वर्ग में एक फ़ील्ड होता है जो स्ट्रीम में नहीं होता है, तो ऑब्जेक्ट में उस फ़ील्ड को उसके प्रकार के लिए डिफ़ॉल्ट मान से आरंभ किया जाएगा। यदि वर्ग-विशिष्ट आरंभीकरण की आवश्यकता है, तो कक्षा एक रीडऑबजेक्ट विधि प्रदान कर सकती है जो फ़ील्ड को नॉनडेफ़ॉल्ट मानों के लिए प्रारंभ कर सकती है।
  • कक्षाएं जोड़ना: धारा में प्रत्येक वस्तु का प्रकार पदानुक्रम होगा। वर्तमान वर्ग के साथ धारा में इस पदानुक्रम की तुलना करने से अतिरिक्त कक्षाओं का पता लगाया जा सकता है। चूंकि उस स्ट्रीम में कोई जानकारी नहीं है जिससे ऑब्जेक्ट को इनिशियलाइज़ करना है, क्लास के फील्ड्स को डिफॉल्ट वैल्यूज़ के लिए इनिशियलाइज़ किया जाएगा।
  • कक्षाएं हटाना: वर्तमान वर्ग के साथ धारा में वर्ग पदानुक्रम की तुलना करने से पता चल सकता है कि एक कक्षा हटा दी गई है। इस स्थिति में, उस वर्ग के अनुरूप फ़ील्ड और ऑब्जेक्ट स्ट्रीम से पढ़े जाते हैं। आदिम क्षेत्रों को छोड़ दिया जाता है, लेकिन हटाए गए वर्ग द्वारा संदर्भित ऑब्जेक्ट बनाए जाते हैं, क्योंकि उन्हें बाद में स्ट्रीम में संदर्भित किया जा सकता है। जब कचरा कचरा एकत्र या रीसेट हो जाएगा तो वे कचरा एकत्र कर लेंगे।
  • राइटऑबजेक्ट / रीडऑब्जेक्ट विधियों को जोड़ना: यदि स्ट्रीम पढ़ने वाले संस्करण में ये विधियाँ हैं तो readObject अपेक्षित है, सामान्य रूप से, डिफ़ॉल्ट क्रमांकन द्वारा स्ट्रीम को लिखे गए आवश्यक डेटा को पढ़ने के लिए। किसी भी वैकल्पिक डेटा को पढ़ने से पहले इसे defaultReadObject को कॉल करना चाहिए। अपेक्षित डेटा लिखने के लिए defaultOriteObject को कॉल करने के लिए हमेशा की तरह राइटऑबजेक्ट विधि अपेक्षित है और फिर वैकल्पिक डेटा लिख सकते हैं।
  • Java.io.Serializable को जोड़ना: यह प्रकार जोड़ने के बराबर है। इस वर्ग के लिए स्ट्रीम में कोई मान नहीं होगा इसलिए इसके फ़ील्ड्स को डिफ़ॉल्ट मानों के लिए आरंभीकृत किया जाएगा। गैर-विचारणीय वर्गों को उप-वर्ग के समर्थन के लिए आवश्यक है कि कक्षा के सुपरपेप्ट में एक न-अर्ग कंस्ट्रक्टर हो और क्लास को ही डिफ़ॉल्ट मानों के लिए आरंभीकृत किया जाएगा। यदि नो-आर्ग कंस्ट्रक्टर उपलब्ध नहीं है, तो InvalidClassException को फेंक दिया जाता है।
  • किसी फ़ील्ड की पहुँच बदलना: एक्सेस मॉडिफायर सार्वजनिक, पैकेज, संरक्षित, और निजी क्षेत्रों में मूल्यों को असाइन करने के लिए क्रमांकन की क्षमता पर कोई प्रभाव नहीं पड़ता है।
  • स्थैतिक से गैर-स्थैतिक या क्षणिक से किसी क्षेत्र में परिवर्तन करना: जब परिवर्तनशील क्षेत्रों की गणना करने के लिए डिफ़ॉल्ट क्रमांकन पर निर्भर होता है, तो यह परिवर्तन वर्ग में फ़ील्ड जोड़ने के बराबर होता है। नया फ़ील्ड स्ट्रीम को लिखा जाएगा, लेकिन पहले की कक्षाएं मूल्य को अनदेखा कर देंगी क्योंकि क्रमिकरण स्थैतिक या क्षणिक क्षेत्रों को मान प्रदान नहीं करेगा।

असंगत परिवर्तन

  • फ़ील्ड हटाना: यदि किसी फ़ील्ड में कोई फ़ील्ड हटा दी जाती है, तो लिखित स्ट्रीम में उसका मान नहीं होगा। जब स्ट्रीम को पहले वाले वर्ग द्वारा पढ़ा जाता है, तो फ़ील्ड का मान डिफ़ॉल्ट मान पर सेट किया जाएगा क्योंकि स्ट्रीम में कोई मान उपलब्ध नहीं है। हालाँकि, यह डिफ़ॉल्ट मान इसके अनुबंध को पूरा करने के लिए पहले वाले संस्करण की क्षमता पर प्रतिकूल प्रभाव डाल सकता है।
  • पदानुक्रम को ऊपर या नीचे ले जाना कक्षाएं: यह अनुमति नहीं दी जा सकती क्योंकि धारा में डेटा गलत अनुक्रम में दिखाई देता है।
  • गैर-स्थैतिक क्षेत्र को स्थैतिक या एक क्षणिक क्षेत्र में क्षणिक में बदलना : जब डिफ़ॉल्ट क्रमांकन पर निर्भर होता है, तो यह परिवर्तन एक क्षेत्र को कक्षा से हटाने के बराबर होता है। कक्षा का यह संस्करण उस डेटा को स्ट्रीम में नहीं लिखेगा, इसलिए यह कक्षा के पुराने संस्करणों द्वारा पढ़ने के लिए उपलब्ध नहीं होगा। किसी क्षेत्र को हटाते समय, पहले वाले संस्करण के क्षेत्र को डिफ़ॉल्ट मान के आधार पर आरंभ किया जाएगा, जिससे कक्षा अप्रत्याशित रूप से विफल हो सकती है।
  • एक आदिम क्षेत्र के घोषित प्रकार को बदलना: कक्षा का प्रत्येक संस्करण अपने घोषित प्रकार के साथ डेटा लिखता है। फ़ील्ड को पढ़ने का प्रयास करने वाले वर्ग के पहले संस्करण विफल हो जाएंगे क्योंकि स्ट्रीम में डेटा का प्रकार फ़ील्ड के प्रकार से मेल नहीं खाता है।
  • राइटऑबजेक्ट या रीडऑबजेक्ट विधि को बदलना ताकि यह अब डिफ़ॉल्ट फ़ील्ड डेटा नहीं लिखता या पढ़ता है या इसे बदल देता है ताकि यह पिछले संस्करण के न होने पर इसे लिखने या इसे पढ़ने का प्रयास करे। डिफ़ॉल्ट फ़ील्ड डेटा को लगातार स्ट्रीम में दिखाई देना चाहिए या दिखाई नहीं देना चाहिए।
  • धारावाहिक से परिवर्तनशील या इसके विपरीत एक वर्ग को बदलना एक असंगत परिवर्तन है क्योंकि धारा में डेटा होगा जो उपलब्ध वर्ग के कार्यान्वयन के साथ असंगत है।
  • एक गैर-एनम प्रकार से एक एनुम प्रकार या इसके विपरीत में एक वर्ग को बदलने के बाद से स्ट्रीम में डेटा होगा जो उपलब्ध वर्ग के कार्यान्वयन के साथ असंगत है।
  • या तो Serializable या Externalizable को हटाना एक असंगत परिवर्तन है, जब यह लिखा जाता है कि यह अब कक्षा के पुराने संस्करणों द्वारा आवश्यक फ़ील्ड की आपूर्ति नहीं करेगा।
  • किसी वर्ग के लिए लिखने की क्रिया या readResolve विधि जोड़ना असंगत है यदि व्यवहार एक ऐसी वस्तु का उत्पादन करेगा जो कक्षा के किसी भी पुराने संस्करण के साथ असंगत है।

जैक्सन के साथ कस्टम JSON देशीकरण

हम JSON प्रारूप के रूप में बाकी API का उपभोग करते हैं और फिर इसे POJO के रूप में अनमार्ट कर देते हैं। जैक्सन के org.codehaus.jackson.map.ObjectMapper बॉक्स से "बस काम करता है" और हम वास्तव में ज्यादातर मामलों में कुछ भी नहीं करते हैं। लेकिन कभी-कभी हमें अपनी कस्टम ज़रूरतों को पूरा करने के लिए कस्टम डीसेरलाइज़र की आवश्यकता होती है और यह ट्यूटोरियल आपको अपना कस्टम डीरिज़ाइज़र बनाने की प्रक्रिया के माध्यम से मार्गदर्शन करेगा।

मान लीजिए कि हमारे पास निम्नलिखित इकाइयाँ हैं।

public class User {
    private Long id;
    private String name;
    private String email;

    //getter setter are omitted for clarity 
}

तथा

public class Program {
    private Long id;
    private String name;
    private User createdBy;
    private String contents;

    //getter setter are omitted for clarity
}

आइए पहले एक वस्तु को क्रमबद्ध करें / मार्शलों करें।

User user = new User();
user.setId(1L);
user.setEmail("[email protected]");
user.setName("Bazlur Rahman");

Program program = new Program();
program.setId(1L);
program.setName("Program @# 1");
program.setCreatedBy(user);
program.setContents("Some contents");

ObjectMapper objectMapper = new ObjectMapper();

अंतिम स्ट्रिंग json = objectMapper.writeValueAsString (प्रोग्राम); Println (json);

उपरोक्त कोड JSON- का उत्पादन करेगा

{
    "id": 1,
    "name": "Program @# 1",
    "createdBy": {
        "id": 1,
        "name": "Bazlur Rahman",
        "email": "[email protected]"
    },
    "contents": "Some contents"
}

अब इसके विपरीत बहुत आसानी से कर सकते हैं। यदि हमारे पास यह JSON है, तो हम ObjectMapper का उपयोग करके किसी प्रोग्राम ऑब्जेक्ट के लिए अनमर्शल कर सकते हैं -

अब हम कहते हैं, यह वास्तविक मामला नहीं है, हम एक एपीआई से एक अलग JSON के लिए जा रहे हैं जो हमारे Program वर्ग के साथ मेल नहीं खाता है।

{
"id": 1,
"name": "Program @# 1",
"ownerId": 1
"contents": "Some contents"
}

JSON स्ट्रिंग को देखें, तो आप देख सकते हैं, इसका एक अलग क्षेत्र है जो कि ओवेनरआईड है।

अब यदि आप इस JSON को क्रमबद्ध करना चाहते हैं जैसा कि हमने पहले किया था, तो आपके पास अपवाद होंगे।

अपवादों से बचने के दो तरीके हैं और यह क्रमबद्ध है -

अज्ञात क्षेत्रों को अनदेखा करें

onwerId अनदेखा करें। प्रोग्राम वर्ग में निम्नलिखित एनोटेशन जोड़ें

@JsonIgnoreProperties(ignoreUnknown = true)
public class Program {}

कस्टम डेज़राइज़र लिखें

लेकिन ऐसे मामले हैं जब आपको वास्तव में इस owerId फ़ील्ड की आवश्यकता होती है। मान लें कि आप इसे User वर्ग की आईडी के रूप में संबंधित करना चाहते हैं।

ऐसे मामले में, आपको एक कस्टम डेज़राइज़र लिखने की ज़रूरत है-

जैसा कि आप देख सकते हैं, सबसे पहले आपको JsonNode से JsonNode को एक्सेस करना JonsParser । और फिर आप आसानी से get() विधि का उपयोग करके एक JsonNode से जानकारी निकाल सकते हैं। और आपको फ़ील्ड नाम के बारे में सुनिश्चित करना होगा। यह सटीक नाम होना चाहिए, वर्तनी की गलती अपवाद का कारण होगी।

और अंत में, आप करने के लिए अपने ProgramDeserializer पंजीकरण कराना होगा ObjectMapper

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Program.class, new ProgramDeserializer());
 
mapper.registerModule(module);
 
String newJsonString = "{\"id\":1,\"name\":\"Program @# 1\",\"ownerId\":1,\"contents\":\"Some contents\"}";
final Program program2 = mapper.readValue(newJsonString, Program.class);

वैकल्पिक रूप से, आप एनोटेशन का उपयोग सीधे डीज़रीलाइज़र को पंजीकृत करने के लिए कर सकते हैं -

@JsonDeserialize(using = ProgramDeserializer.class)
public class Program {
}


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow