根据类型跳过空值的序列化

Skipping serialization of null values depending on the type

几周前我开始使用 moshi,所以也许我遗漏了一些微不足道的东西,但我已经花了很多时间试图解决这个问题但没有成功,所以这是我的问题。

具有以下可重现的代码:

fun main() {

    val moshi = Moshi.Builder().add(OptionalAdapter).build()
    val objectToSerialize = DummyObject()
    val json = moshi.adapter(DummyObject::class.java).serializeNulls().toJson(objectToSerialize)
    println(json)

}

@JsonClass(generateAdapter = true)
data class DummyObject(val value: Int=123, val someNullable: String? = null,
                       val someNotPresent: Optional<String> = Optional.NotPresent,
                       val somePresent: Optional<String> = Optional.Present("aaaa"))


class OptionalAdapter<T>(private val valueAdapter: JsonAdapter<T>) : JsonAdapter<Optional<T>>() {
    @Suppress("UNCHECKED_CAST")
    override fun fromJson(reader: JsonReader) = Optional.Present(valueAdapter.fromJson(reader) as T)

    override fun toJson(writer: JsonWriter, value: Optional<T>?) {
        when (value) {
            is Optional.NotPresent -> writer.nullValue()
            is Optional.Present -> valueAdapter.serializeNulls().toJson(writer, value.value)
        }
    }

    companion object Factory : JsonAdapter.Factory {
        override fun create(type: Type, annotations: Set<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
            return if (Types.getRawType(type) == Optional::class.java && annotations.isEmpty()) {
                val valueType = if(type is ParameterizedType) {
                    type.actualTypeArguments.get(0)
                } else {
                    //Should not happen
                    throw IllegalArgumentException()
                }
                return OptionalAdapter(moshi.adapter<Any>(valueType).nullSafe())
            } else {
                null
            }
        }
    }
}

sealed class Optional<out T> {
    val provided get() = this !is NotPresent
    abstract val value: T

    object NotPresent : Optional<Nothing>() {
        // have the IDE raise an error if the user knows a type is missing but still tries to access a value
        @Deprecated(
            "Cannot access a missing value",
            level = DeprecationLevel.ERROR,
            replaceWith = ReplaceWith("TODO(\"value is missing\")")
        )
        override val value: Nothing
            get() = error("cannot access provided field")
    }

    data class Present<out T>(override val value: T) : Optional<T>()
}

我想序列化为 {"value":123,"someNullable":null,"somePresent":"aaaa"} 而不是 {"value":123,"someNullable":null,"someNotPresent":null,"somePresent":"aaaa"},这是现在正在做的。

基本上,如果类型是 Optional.NotPresent,我想跳过序列化。有什么建议吗?

我最终得到的解决方案:

override fun toJson(writer: JsonWriter, value: Optional<T>?) {
        when (value) {
            is Optional.NotPresent -> {
                val wasSerializeNulls = writer.serializeNulls
                writer.serializeNulls = false
                try {
                    writer.nullValue()
                } finally {
                    writer.serializeNulls = wasSerializeNulls
                }
            }
            is Optional.Present -> valueAdapter.serializeNulls().toJson(writer, value.value)
        }
    }