ऑब्जेक्ट निर्माता के बिना डिफॉल्ट कंस्ट्रक्टर के बिना किसी अपरिवर्तनीय ऑब्जेक्ट को डी / सीरियल कैसे करें?


106

मैं com.fasterxml.jackson.databind.ObjectMapper का उपयोग करके एक अपरिवर्तनीय वस्तु को क्रमबद्ध और निष्क्रिय करना चाहता हूं।

अपरिवर्तनीय वर्ग इस तरह दिखता है (सिर्फ 3 आंतरिक गुण, गेटर्स और कंस्ट्रक्टर):

public final class ImportResultItemImpl implements ImportResultItem {

    private final ImportResultItemType resultType;

    private final String message;

    private final String name;

    public ImportResultItemImpl(String name, ImportResultItemType resultType, String message) {
        super();
        this.resultType = resultType;
        this.message = message;
        this.name = name;
    }

    public ImportResultItemImpl(String name, ImportResultItemType resultType) {
        super();
        this.resultType = resultType;
        this.name = name;
        this.message = null;
    }

    @Override
    public ImportResultItemType getResultType() {
        return this.resultType;
    }

    @Override
    public String getMessage() {
        return this.message;
    }

    @Override
    public String getName() {
        return this.name;
    }
}

हालाँकि जब मैं यह इकाई परीक्षण चलाता हूँ:

@Test
public void testObjectMapper() throws Exception {
    ImportResultItemImpl originalItem = new ImportResultItemImpl("Name1", ImportResultItemType.SUCCESS);
    String serialized = new ObjectMapper().writeValueAsString((ImportResultItemImpl) originalItem);
    System.out.println("serialized: " + serialized);

    //this line will throw exception
    ImportResultItemImpl deserialized = new ObjectMapper().readValue(serialized, ImportResultItemImpl.class);
}

मुझे यह अपवाद मिलता है:

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class eu.ibacz.pdkd.core.service.importcommon.ImportResultItemImpl]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: {"resultType":"SUCCESS","message":null,"name":"Name1"}; line: 1, column: 2]
    at 
... nothing interesting here

यह अपवाद मुझे एक डिफ़ॉल्ट निर्माणकर्ता बनाने के लिए कहता है, लेकिन यह एक अपरिवर्तनीय वस्तु है, इसलिए मैं ऐसा नहीं करना चाहता। यह आंतरिक विशेषताओं को कैसे निर्धारित करेगा? यह पूरी तरह से एपीआई के उपयोगकर्ता को भ्रमित करेगा।

तो मेरा सवाल यह है: क्या मैं किसी भी तरह डिफ़ॉल्ट ऑब्जेक्ट्स के बिना अपरिवर्तनीय वस्तुओं को क्रमबद्ध / अनुक्रमित कर सकता हूं?


डीसर्लाइज़ करते समय, डीस्लाइज़र आपके किसी भी कंस्ट्रक्टर के बारे में नहीं जानता है, इसलिए यह डिफॉल्ट कंस्ट्रक्टर को हिट करता है। इसके कारण आपको एक डिफ़ॉल्ट निर्माता बनाना होगा, जो अपरिवर्तनीयता को नहीं बदलेगा। इसके अलावा, मैं देखता हूं कि क्लास फाइनल नहीं है, ऐसा क्यों? किसी को भी कार्यक्षमता को ओवरराइड कर सकते हैं यह नहीं है?
अभिनबा बसु

कक्षा अंतिम नहीं है, क्योंकि मैं इसे वहां लिखना भूल गया था, आपको धन्यवाद देने के लिए धन्यवाद :)
मीकल

जवाबों:


149

जैक्सन को यह बताने के लिए कि वशीकरण के लिए एक वस्तु कैसे बनाई जाए, अपने निर्माणकर्ताओं के लिए @JsonCreatorऔर @JsonPropertyइस तरह से एनोटेशन का उपयोग करें:

@JsonCreator
public ImportResultItemImpl(@JsonProperty("name") String name, 
        @JsonProperty("resultType") ImportResultItemType resultType, 
        @JsonProperty("message") String message) {
    super();
    this.resultType = resultType;
    this.message = message;
    this.name = name;
}

1
+1 धन्यवाद सर्गेई। यह काम किया .. हालांकि मुझे JsonCreator एनोटेशन का उपयोग करने के बाद भी समस्या हो रही थी .. लेकिन कुछ समीक्षा के बाद मुझे एहसास हुआ कि मैं अपने संसाधन में RequestBody एनोटेशन का उपयोग करना भूल गया। अब यह काम करता है .. एक बार फिर थैंक्स।
राहुल

4
क्या आप एक डिफ़ॉल्ट निर्माता, या नहीं जोड़ सकते, तो @JsonCreatorऔर @JsonPropertyएनोटेशन क्योंकि आप इसे बदलने के लिए POJO के लिए उपयोग नहीं है? वहाँ अभी भी वस्तु deserialize करने के लिए एक रास्ता है?
जैक स्ट्रॉ

1
@JackStraw 1) ऑब्जेक्ट से सबक्लास और सभी गेटर्स और सेवर्स को ओवरराइड करता है। 2) कक्षा के लिए अपना स्वयं का सीरियलसेलर / डिसेरलाइज़र लिखें और इसका उपयोग करें ("कस्टम सीरियलाइज़र" के लिए खोज 3) ऑब्जेक्ट को लपेटें और एक प्रॉपर्टी के लिए सिर्फ़ एक धारावाहिक / डिसेरिज़ाइज़र लिखें (यह आपको एक सीरियल लिखने वाले से कम काम करने दे सकता है) वर्ग ही, लेकिन शायद नहीं)।
ErikE

+1 आपकी टिप्पणी ने मुझे बचा लिया! अब तक हर समाधान जो मुझे मिल रहा था, वह डिफॉल्ट कंस्ट्रक्टर था ...
निल्सन अगुएर

34

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

संपादित करें: और यदि आपके पास विरासत है, तो मूल वर्गों के लिए एक संरक्षित / पैकेज-संरक्षित डिफ़ॉल्ट निर्माता का उपयोग करें।


बस इस उत्तर पर निर्माण करने के लिए, यदि आप जिस वर्ग को अलग करना चाहते हैं वह किसी अन्य वर्ग का विस्तार करता है तो आप सुपर क्लास (या दोनों वर्गों) के डिफ़ॉल्ट निर्माता को संरक्षित कर सकते हैं।
KWILLIAMS

3

सर्गेई पेटुनिन का पहला उत्तर सही है। हालाँकि, हम निर्माण के प्रत्येक पैरामीटर पर अनावश्यक @JsonProperty एनोटेशन को हटाने के साथ कोड को सरल बना सकते हैं।

यह com.fasterxml.jackson.module.paramnames.ParameterNamesModule को ObjectMapper में जोड़ने के साथ किया जा सकता है:

new ObjectMapper()
        .registerModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))

(Btw: इस मॉड्यूल को स्प्रिंगबूट में डिफ़ॉल्ट रूप से पंजीकृत किया गया है। यदि आप JacksonObjectMapperConfiguration से ObjectMapper बीन का उपयोग करते हैं या यदि आप सेम के साथ अपना खुद का ObjectMapper बनाते हैं।

उदाहरण के लिए:

public class FieldValidationError {
  private final String field;
  private final String error;

  @JsonCreator
  public FieldValidationError(String field,
                              String error) {
    this.field = field;
    this.error = error;
  }

  public String getField() {
    return field;
  }

  public String getError() {
    return error;
  }
}

और ObjectMapper बिना किसी त्रुटि के इस जंस का वर्णन करता है:

{
  "field": "email",
  "error": "some text"
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.