परिचय: आपका Kotlin कोड अचानक Jackson को क्यों "तोड़" देता है?
\n\nक्या आपने कभी Kotlin में एक सुंदर, संक्षिप्त data class लिखा है, उसमें कुछ फ़ील्ड जोड़े हैं, Jackson के माध्यम से JSON डिसीरियलाइज़ेशन चलाया है — और अचानक एक लंबी, डरावनी त्रुटि मिली है? परिचित लगता है? यदि हाँ, तो आप अकेले नहीं हैं। त्रुटि "No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator" Java से Kotlin पर स्विच करने वाले डेवलपर्स के बीच Stack Overflow पर सबसे लोकप्रिय प्रश्नों में से एक है (हज़ारों व्यू!)।
इस लेख में, हम केवल त्रुटि का अनुवाद नहीं करेंगे। हम इसे "माइक्रोस्कोप के नीचे" रखेंगे: यह क्यों होती है, इसे कैसे दोहराया जाए, और सबसे महत्वपूर्ण बात — इससे हमेशा के लिए कैसे छुटकारा पाया जाए। आपको न केवल सिद्धांत मिलेगा, बल्कि Kotlin कोड के साथ तैयार, सिद्ध समाधान भी मिलेंगे। चलिए शुरू करते हैं!
\n\nइस त्रुटि का वास्तव में क्या मतलब है? सरल शब्दों में
\n\nमान लीजिए कि Jackson एक "बिल्डर" है जिसे JSON की ईंटों से आपके क्लास का ऑब्जेक्ट बनाना है। घर बनाने के लिए, बिल्डर को एक स्पष्ट योजना (कंस्ट्रक्टर) या कम से कम तैयार दीवारों (फ़ील्ड) का एक सेट चाहिए।
\n\nत्रुटि "No Creators, like default construct, exist" का शाब्दिक अर्थ है: "प्रिय Jackson, मैं इस क्लास का ऑब्जेक्ट नहीं बना सकता क्योंकि इसका कोई डिफ़ॉल्ट कंस्ट्रक्टर (बिना पैरामीटर के) नहीं है, और मुझे नहीं पता कि इसे दिए गए JSON फ़ील्ड से कैसे बनाया जाए!"
\n\nJava में, सब कुछ सरल है: यदि आपने कोई कंस्ट्रक्टर नहीं लिखा है, तो कंपाइलर स्वचालित रूप से एक खाली डिफ़ॉल्ट कंस्ट्रक्टर बनाता है। Jackson इसे देखता है और खुशी से उपयोग करता है। Kotlin में, यदि आप कंस्ट्रक्टर में पैरामीटर के साथ data class परिभाषित करते हैं, तो बिना पैरामीटर वाला कंस्ट्रक्टर स्वचालित रूप से नहीं बनता है। और Jackson, डिफ़ॉल्ट रूप से, उसी की तलाश करता है।
समस्या को दोहराना: वह कोड जो त्रुटि देगा
\n\nआइए एक सरल उदाहरण लिखें जो निश्चित रूप से यह त्रुटि उत्पन्न करेगा। मान लीजिए कि हमारे पास एक उपयोगकर्ता क्लास है:
\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\n\n// ध्यान दें: यह कोड त्रुटि उत्पन्न करेगा!\ndata class User(val name: String, val age: Int)\n\nfun main() {\n val mapper: ObjectMapper = jacksonObjectMapper()\n val json = """{"name": "Алексей", "age": 30}"""\n\n // JSON को User ऑब्जेक्ट में डिसीरियलाइज़ करने का प्रयास\n val user: User = mapper.readValue(json)\n println(user)\n}\n\n\nइस कोड को चलाएँ, और आपको वह प्रसिद्ध अपवाद मिलेगा:
\n\ncom.fasterxml.jackson.databind.exc.InvalidDefinitionException: \nCannot construct instance of `User` (no Creators, like default construct, exist): \ncannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (String)"{"name": "Алексей", "age": 30}"; line: 1, column: 2]\n\n\nयह रहा, हमारा Stack Overflow का "सितारा"! ऐसा क्यों हुआ? क्योंकि data class User(val name: String, val age: Int) में बिना पैरामीटर वाला कोई कंस्ट्रक्टर नहीं है। इसके सभी फ़ील्ड प्राथमिक कंस्ट्रक्टर में घोषित हैं, और वे अनिवार्य हैं (val)। Jackson User नहीं बना सकता, क्योंकि उसे नहीं पता कि name और age में कौन से मान देने हैं, और उसके पास सेटर के रूप में कोई संकेत नहीं है।
त्रुटि को ठीक करने के 3 तरीके (सरल से सही तक)
\n\nअच्छी खबर: कई समाधान हैं। चुनाव इस बात पर निर्भर करता है कि आप प्रक्रिया को कितना नियंत्रित करना चाहते हैं और आप किस कोड को "स्वच्छ" मानते हैं।
\n\nतरीका 1: सबसे सरल (लेकिन Kotlin शुद्धतावादियों के लिए नहीं)
\n\nमैन्युअल रूप से बिना पैरामीटर वाला कंस्ट्रक्टर जोड़ें। Kotlin में, यह सभी फ़ील्ड के लिए डिफ़ॉल्ट मान निर्दिष्ट करके किया जाता है।
\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\n\n// हाँ