Gson serialize null for specific class or field

后端 未结 5 457
面向向阳花
面向向阳花 2021-01-01 11:00

I want to serialize nulls for a specific field or class.

In GSON, the option serializeNulls() applies to the whole JSON.

Example:



        
5条回答
  •  抹茶落季
    2021-01-01 11:50

    I have a solution similar to the one of Aleksey but that can be applied to one or more fields in any class (example in Kotlin):

    Create a new annotation for fields that should be serialized as null:

    @Retention(AnnotationRetention.RUNTIME)
    @Target(AnnotationTarget.FIELD)
    annotation class SerializeNull
    

    Create a TypeAdapterFactory that checks if a class has fields annotated with this annotation and removes the fields that are null and not annotated with the annotation from the JsonTree when writing the object:

    class SerializableAsNullConverter : TypeAdapterFactory {
    
        override fun  create(gson: Gson, type: TypeToken): TypeAdapter? {
            fun Field.serializedName() = declaredAnnotations
                .filterIsInstance()
                .firstOrNull()?.value ?: name
            val declaredFields = type.rawType.declaredFields
            val nullableFieldNames = declaredFields
                .filter { it.declaredAnnotations.filterIsInstance().isNotEmpty() }
                .map { it.serializedName() }
            val nonNullableFields = declaredFields.map { it.serializedName() } - nullableFieldNames
    
            return if (nullableFieldNames.isEmpty()) {
                null
            } else object : TypeAdapter() {
                private val delegateAdapter = gson.getDelegateAdapter(this@SerializableAsNullConverter, type)
                private val elementAdapter = gson.getAdapter(JsonElement::class.java)
    
                override fun write(writer: JsonWriter, value: T?) {
                    val jsonObject = delegateAdapter.toJsonTree(value).asJsonObject
                    nonNullableFields
                        .filter { jsonObject.get(it) is JsonNull }
                        .forEach { jsonObject.remove(it) }
                    val originalSerializeNulls = writer.serializeNulls
                    writer.serializeNulls = true
                    elementAdapter.write(writer, jsonObject)
                    writer.serializeNulls = originalSerializeNulls
                }
    
                override fun read(reader: JsonReader): T {
                    return delegateAdapter.read(reader)
                }
            }
        }
    }
    

    Register the adapter with your Gson instance:

    val builder = GsonBuilder().registerTypeAdapterFactory(SerializableAsNullConverter())
    

    And annotate the fields you would like to be nullable:

    class MyClass(val id: String?, @SerializeNull val name: String?)
    

    Serialization result:

    val myClass = MyClass(null, null)
    val gson = builder.create()
    val json = gson.toJson(myClass)
    

    json:

    {
        "name": null
    }
    

提交回复
热议问题