【问题标题】:How to encode a field of an object as stringifed JSON instead of nested JSON object in Moshi?如何将对象的字段编码为字符串化 JSON 而不是 Moshi 中的嵌套 JSON 对象?
【发布时间】:2019-11-08 16:28:35
【问题描述】:

我有一个密封类WebSocketMessage,它有一些子类。 WebSocketMessage 有一个名为 type 的字段,用于区分子类。

所有子类都有自己的字段payload,每个子类的类型不同。

目前我正在使用 Moshi 的 PolymorphicJsonAdapterFactory,以便这些类可以从 JSON 解析并编码为 JSON。

这一切都有效,但我需要将 payload 字段编码为字符串化 JSON 而不是 JSON 对象。

是否有可能编写一个自定义适配器类来帮助我解决这个问题?或者有没有其他解决方案,这样我就不必手动进行这种字符串化了?

我曾尝试研究自定义适配器,但我找不到如何将 moshi 实例传递给适配器,以便我可以将给定字段编码为 JSON,然后对其进行字符串化,我也找不到任何其他可以帮助我的东西。

WebSocketMessage 类及其子类:


sealed class WebSocketMessage(
    val type: Type
) {
    enum class Type(val type: String) {
        AUTH("AUTH"),
        PING("PING"),
        FLOW_INITIALIZATION("FLOW_INITIALIZATION")
    }

    class Ping : WebSocketMessage(Type.PING)
    class InitFlow(payload: InitFlowMessage) : WebSocketMessage(Type.FLOW_INITIALIZATION)
    class Auth(payload: Token) : WebSocketMessage(Type.AUTH)
}

PolymorphicJsonAdapterFactory 的 Moshi 实例:

val moshi = Moshi.Builder().add(
                    PolymorphicJsonAdapterFactory.of(WebSocketMessage::class.java, "type")
                        .withSubtype(WebSocketMessage.Ping::class.java, WebSocketMessage.Type.PING.type)
                        .withSubtype(
                            WebSocketMessage.InitFlow::class.java,
                            WebSocketMessage.Type.FLOW_INITIALIZATION.type
                        )                        
                        .withSubtype(WebSocketMessage.Auth::class.java, WebSocketMessage.Type.AUTH.type)
                )
                // Must be added last
                .add(KotlinJsonAdapterFactory())
                .build()

我如何编码为 JSON:

moshi.adapter(WebSocketMessage::class.java).toJson(WebSocketMessage.Auth(fetchToken()))

我目前得到下一个格式的 JSON:

{  
   "type":"AUTH",
   "payload":{  
      "jwt":"some_token"
   }
}

我想得到什么:

{  
   "type":"AUTH",
   "payload":"{\"jwt\":\"some_token\"}"
}

在第二个示例中,有效负载是一个字符串化的 JSON 对象,这正是我所需要的。

【问题讨论】:

    标签: android kotlin moshi


    【解决方案1】:

    您可以创建自己的自定义JsonAdapter

    @Retention(AnnotationRetention.RUNTIME)
    @JsonQualifier
    annotation class AsString
    
    /////////////////////
    
    class AsStringAdapter<T>(
        private val originAdapter: JsonAdapter<T>,
        private val stringAdapter: JsonAdapter<String>
    ) : JsonAdapter<T>() {
    
        companion object {
    
            var FACTORY: JsonAdapter.Factory = object : Factory {
                override fun create(
                    type: Type,
                    annotations: MutableSet<out Annotation>,
                    moshi: Moshi
                ): JsonAdapter<*>? {
                    val nextAnnotations = Types.nextAnnotations(annotations, AsString::class.java)
                    return if (nextAnnotations == null || !nextAnnotations.isEmpty())
                        null else {
                        AsStringAdapter(
                            moshi.nextAdapter<Any>(this, type, nextAnnotations),
                            moshi.nextAdapter<String>(this, String::class.java, Util.NO_ANNOTATIONS)
                        )
                    }
                }
            }
        }
    
        override fun toJson(writer: JsonWriter, value: T?) {
            val jsonValue = originAdapter.toJsonValue(value)
            val jsonStr = JSONObject(jsonValue as Map<*, *>).toString()
            stringAdapter.toJson(writer, jsonStr)
        }
    
        override fun fromJson(reader: JsonReader): T? {
            throw UnsupportedOperationException()
        }
    }
    
    /////////////////////
    
    class Auth(@AsString val payload: Token)
    
    /////////////////////
    
    .add(AsStringAdapter.FACTORY)
    .add(KotlinJsonAdapterFactory())
    .build()
    

    【讨论】:

    • 在工厂的onCreate 方法中,你的意思是写nextAnnotations.isEmpty() 而不是!nextAnnotations.isEmpty()
    • 我现在看到,当我将代码更改为 nextAnnotations.isEmpty() 而不是您编写它的方式时,程序失败了。
    • Types#nextAnnotations 返回没有 jsonQualifier 的注解子集,如果注解不包含 jsonQualifier,则返回 null
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 2022-01-20
    • 1970-01-01
    • 2011-10-12
    • 2021-08-20
    • 2021-02-05
    • 1970-01-01
    相关资源
    最近更新 更多