जिस समस्या को मैं हल करने का प्रयास कर रहा हूं, वह यह लिंक:

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

वह पोस्ट एक समाधान प्रस्तुत करता है लेकिन kotlinx.serialization लाइब्रेरी का उपयोग करते हुए, हालांकि, मुझे अभी के लिए gson लाइब्रेरी का उपयोग करना चाहिए।

इसलिए मैं अपने स्वयं के समाधान को लागू करने की कोशिश कर रहा हूं क्योंकि मुझे ऐसा कुछ भी नहीं मिला जो मेरे उपयोग के मामले में उपयुक्त हो (कृपया मुझे बताएं कि क्या है)।

data class MyObject(
    val fieldOne: OptionalProperty<String> = OptionalProperty.NotPresent,
    val fieldTwo: OptionalProperty<String?> = OptionalProperty.NotPresent,
    val fieldThree: OptionalProperty<Int> = OptionalProperty.NotPresent
)

fun main() {
    val gson = GsonBuilder()
        .registerTypeHierarchyAdapter(OptionalProperty::class.java, OptionalPropertyDeserializer())
        .create()
    val json1 = """{
            "fieldOne": "some string",
            "fieldTwo": "another string",
            "fieldThree": 18
        }
        """
    println("json1 result object: ${gson.fromJson(json1, MyObject::class.java)}")
    val json2 = """{
            "fieldOne": "some string",
            "fieldThree": 18
        }
        """
    println("json2 result object: ${gson.fromJson(json2, MyObject::class.java)}")
    val json3 = """{
            "fieldOne": "some string",
            "fieldTwo": null,
            "fieldThree": 18
        }
        """
    println("json3 result object: ${gson.fromJson(json3, MyObject::class.java)}")

}

sealed class OptionalProperty<out T> {

    object NotPresent : OptionalProperty<Nothing>()

    data class Present<T>(val value: T) : OptionalProperty<T>()
}

class OptionalPropertyDeserializer : JsonDeserializer<OptionalProperty<*>> {

    private val gson: Gson = Gson()

    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): OptionalProperty<*> {
        println("Inside OptionalPropertyDeserializer.deserialize json:$json")
        return when {
            // Is it a JsonObject? Bingo!
            json?.isJsonObject == true ||
                    json?.isJsonPrimitive == true-> {

                // Let's try to extract the type in order
                // to deserialize this object
                val parameterizedType = typeOfT as ParameterizedType

                // Returns an Present with the value deserialized
                return OptionalProperty.Present(
                    context?.deserialize<Any>(
                        json,
                        parameterizedType.actualTypeArguments[0]
                    )!!
                )
            }
            // Wow, is it an array of objects?
            json?.isJsonArray == true -> {

                // First, let's try to get the array type
                val parameterizedType = typeOfT as ParameterizedType

                // check if the array contains a generic type too,
                // for example, List<Result<T, E>>
                if (parameterizedType.actualTypeArguments[0] is WildcardType) {

                    // In case of yes, let's try to get the type from the
                    // wildcard type (*)
                    val internalListType = (parameterizedType.actualTypeArguments[0] as WildcardType).upperBounds[0] as ParameterizedType

                    // Deserialize the array with the base type Any
                    // It will give us an array full of linkedTreeMaps (the json)
                    val arr = context?.deserialize<Any>(json, parameterizedType.actualTypeArguments[0]) as ArrayList<*>

                    // Iterate the array and
                    // this time, try to deserialize each member with the discovered
                    // wildcard type and create new array with these values
                    val result = arr.map { linkedTreeMap ->
                        val jsonElement = gson.toJsonTree(linkedTreeMap as LinkedTreeMap<*, *>).asJsonObject
                        return@map context.deserialize<Any>(jsonElement, internalListType.actualTypeArguments[0])
                    }

                    // Return the result inside the Ok state
                    return OptionalProperty.Present(result)
                } else {
                    // Fortunately it is a simple list, like Array<String>
                    // Just get the type as with a JsonObject and return an Ok
                    return OptionalProperty.Present(
                        context?.deserialize<Any>(
                            json,
                            parameterizedType.actualTypeArguments[0]
                        )!!
                    )
                }
            }
            // It is not a JsonObject or JsonArray
            // Let's returns the default state NotPresent.
            else -> OptionalProperty.NotPresent
        }
    }

}

मुझे कस्टम deserializer के अधिकांश कोड यहां से मिले हैं। .

जब मैं main फ़ंक्शन चलाता हूं तो यह आउटपुट होता है:

Inside OptionalPropertyDeserializer.deserialize json:"some string"
Inside OptionalPropertyDeserializer.deserialize json:"another string"
Inside OptionalPropertyDeserializer.deserialize json:18
json1 result object: MyObject(fieldOne=Present(value=some string), fieldTwo=Present(value=another string), fieldThree=Present(value=18))
Inside OptionalPropertyDeserializer.deserialize json:"some string"
Inside OptionalPropertyDeserializer.deserialize json:18
json2 result object: MyObject(fieldOne=Present(value=some string), fieldTwo=my.package.OptionalProperty$NotPresent@573fd745, fieldThree=Present(value=18))
Inside OptionalPropertyDeserializer.deserialize json:"some string"
Inside OptionalPropertyDeserializer.deserialize json:18
json3 result object: MyObject(fieldOne=Present(value=some string), fieldTwo=null, fieldThree=Present(value=18))

मैं fieldTwo के लिए विभिन्न विकल्पों का परीक्षण कर रहा हूं और यह लगभग पूरी तरह से काम कर रहा है, तीसरे जोंस के अपवाद के साथ, जहां मैं उम्मीद करूंगा कि फ़ील्ड दो fieldTwo=null के बजाय fieldTwo=Present(value=null) होना चाहिए।

और मैं देखता हूं कि इस स्थिति में, कस्टम deserializer को fieldTwo के लिए भी नहीं बुलाया जाता है।

क्या कोई यहां देख सकता है कि मुझे क्या याद आ रही है? किसी भी टिप की बहुत सराहना की जाएगी!

0
amp 12 जिंदा 2021, 21:21

1 उत्तर

सबसे बढ़िया उत्तर

मैंने जीसन को छोड़ दिया और मोशी की ओर बढ़ गया।

मैंने इस व्यवहार को इस टिप्पणी में प्रस्तुत समाधान के आधार पर कार्यान्वित किया।

0
amp 14 जिंदा 2021, 19:31