程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了使用 Kotlin lenient Json Serialization 时如何报告未知的 json 字段大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决使用 Kotlin lenient Json serialization 时如何报告未知的 json 字段?

开发过程中遇到使用 Kotlin lenient Json serialization 时如何报告未知的 json 字段的问题如何解决?下面主要结合日常开发的经验,给出你关于使用 Kotlin lenient Json serialization 时如何报告未知的 json 字段的解决方法建议,希望对你解决使用 Kotlin lenient Json serialization 时如何报告未知的 json 字段有所启发或帮助;

我当前的项目采用改造 kotlin Json 序列化。

我已将 Json 配置如下:-

杰森{ ignoreUnkNownKeys = true isLenIEnt = true }

这允许我的应用程序解析带有未知字段的 Json,但是我想报告

我收到的所有未知 Json 字段。

我看不出有什么方法可以实现这一目标。

使用 Jackson 更快的 xml Json 库,这很容易实现,但我希望尽可能少地使用 3rd 方库。

有什么办法可以让 Json 序列化并捕获所有未知的 Json 字段吗?

解决方法

像 the other answer 一样,我将在此答案中发布的代码比我推荐的正确解决方案更像是一种黑客攻击,但与其他答案不同:

  1. 它报告所有未知字段。
  2. 不依赖异常处理逻辑(我预计这会显着增加运行时间并且是一种代码异味)。
  3. 如果您要允许/记录未知字段的可序列化对象的成员有限,则可能适用。

也就是说,真正的解决方案可能是 kotlinx.serialization 库 and I encourage you to post a feature @R_675_10613@est on GitHub 中缺少的功能。维护人员非常积极响应并乐于接受建议!

从源代码 jccampanero linked to in comments 中可以看出,引入此行为的正确抽象级别应在 StreamingJsonDecoder 中。因此,与下面的解决方案不同的解决方案是 to implement a custom format 并复制/粘贴所有 Json 代码,并在 StreamingJsonDecoder.handleUnknown 中添加少量代码。同样,不是我推荐的东西。

以下内容可能适用于 (3) 的情况。

abstract class ReportUnknownFieldsserializer<T : Any>(
    private val tserializer: Kserializer<T>
) : JsonTransformingserializer<T>( tserializer )
{
    override fun transformDeserialize( element: JsonElement ): JsonElement
    {
        if ( element is JsonObject )
        {
            val expectedNames = tserializer.descriptor.elementNames
            val actualNames = element.keys
            val unexpectedNames = actualNames.minus( expectedNames )

            println( unexpectedNames )
        }

        return element
    }
}

@serializable
data class SomeObject( val expected: String )

object SomeObjectserializer
    : ReportUnknownFieldsserializer<SomeObject>( SomeObject.serializer() )

@serializable
data class Wrapper(
    @serializable( SomeObjectserializer::class )
    val someObject: SomeObject
)


class ReportUnknownFieldsserializerTest
{
    @Test
    fun unknown_fields_are_reported()
    {
        val json = Json { ignoreUnknownKeys = true; isLenient = true }

        val serialized = """{"someObject":{"expected":"normal","unexpected":"oh"}}"""

        // Outputs "[unexpected]"
        val wrapper: Wrapper = json.decodeFromString( serialized )
    }
}

一个 JsonTransformingserializer is used,它在反序列化时将预期的字段名称与指定的字段名称进行比较。对于要启用此行为的每个可序列化类成员,您需要应用基 ReportUnknownFieldserializer 的实例化。

因此,如前所述,这可能不适用于您的实际用例。您不想为每个成员字段类型创建自定义序列化程序,然后您必须无处不在。如果这是您的用例,您可能希望将其作为 JSON 序列化格式的一项功能请求给 kotlinx.serialization 的维护者。它可能会涉及 Json 类上的额外配置选项,例如,以您喜欢的任何方式处理未知字段的 lambda 回调。

,

您可以使用以下解决方法:将您的 Json 格式包装成另一种格式,它将尝试以严格的方式(使用 ignoreUnknownKeys = false)解码输入字符串,如果失败,则报告未知键并回退到原始 Json 格式。

@ExperimentalserializationApi
class JsonLoggingUnknownFields(private val kotlinx: Json) : StringFormat by kotlinx {
    private val kotlinxStrict = Json(from = kotlinX) { ignoreUnknownKeys = false }

    override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>,String: String): T {
        val json = kotlinx.parseToJsonElement(String)
        return try {
            kotlinxStrict.decodeFromJsonElement(deserializer,json)
        } catch (e: serializationException) {
            val unknownKeysInTopLevelJsonObject = if (json is JsonObject) {
                val actualFields = json.keys
                val expectedFields = deserializer.descriptor.elementNames
                actualFields - expectedFields
            } else emptySet()

            log.debug(
                if (unknownKeysInTopLevelJsonObject.isnotEmpty()) "Encountered unknown keys: $unknownKeysInTopLevelJsonObject\nCurrent input: $String"
                else e.message!!.replace("Use 'ignoreUnknownKeys = true' in 'Json {}' builder to ignore unknown keys.\n","")
            )

            kotlinx.decodeFromJsonElement(deserializer,json)
        }
    }
}

请注意,此技巧将仅针对顶级 JSON 对象报告所有未知的 JSON 字段,对于嵌套的 JSON 对象(或 JSON 数组)仅第一个遇到未知的字段将被报告(如果顶级 JSON 对象中没有未知字段)。

用法:

@serializable
data class Obj(val x: Int = 0)

@serializable
data class obj2(val obj: Obj)

@ExperimentalserializationApi
fun main() {
    val kotlinx = Json {
        ignoreUnknownKeys = true
        isLenient = true
    }
    val kotlinxWithLogging = JsonLoggingUnknownFields(kotlinX)

    val input1 = "{\"unknownkey1\": 1,\"unknownKey2\": 1,\"x\" : 11}"
    println(kotlinxWithLogging.decodeFromString<Obj>(input1)) //Encountered unknown keys: [unknownkey1,unknownKey2]
    val input2 = "[{\"unknownkey1\": 1,\"unknownKey2\": 1}]"
    println(kotlinxWithLogging.decodeFromString<List<Obj>>(input2)) //Encountered unknown key 'unknownkey1'.
    val input3 = "{\"obj\": {\"unknownkey1\": 1,\"unknownKey2\": 1}}"
    println(kotlinxWithLogging.decodeFromString<obj2>(input3)) //Encountered unknown key 'unknownkey1'.
}

大佬总结

以上是大佬教程为你收集整理的使用 Kotlin lenient Json Serialization 时如何报告未知的 json 字段全部内容,希望文章能够帮你解决使用 Kotlin lenient Json Serialization 时如何报告未知的 json 字段所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。