【问题标题】:How to deserialize raw JSON objects with Moshi/Retrofit如何使用 Moshi/Retrofit 反序列化原始 JSON 对象
【发布时间】:2020-10-31 14:59:24
【问题描述】:

我有一个 Sticker 类及其包装器:

@JsonClass(generateAdapter = true)
class StickerDto(
        @Json (name = "totalAnimatedStickers") val total: Int,
        @Json(name = "pages") val pages: Int,
        @Json(name = "data") val stickers: List<Sticker>

)

@JsonClass(generateAdapter = true)
class Sticker(
        @Json(name = "name") val name: String,
        @Json(name = "id") val id: String,
        @Json(name = "stickerData") val stickerData: JsonObject,
        var isSelected:Boolean = false
)

stickerData 属性来自带有未知属性的动态 json 对象的 api

"stickerData": {}

如何使用 Moshi 反序列化这样的对象?

我目前的改造客户:

 private fun createNewFriendsClient(authRefreshClient: AuthRefreshClient,
                                       preferencesInteractor: PreferencesInteractor): FriendsApiClient {

        val logger = run {
            val httpLoggingInterceptor = HttpLoggingInterceptor()
            httpLoggingInterceptor.apply {
                httpLoggingInterceptor.level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
            }
        }

        val okHttp = OkHttpClient.Builder().addInterceptor(logger).authenticator(RefreshUserAuthenticator(authRefreshClient, preferencesInteractor,
                UnauthorizedNavigator(SDKInternal.appContext, Interactors.preferences))).build()


        return Retrofit.Builder()
                .client(okHttp)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(MoshiConverterFactory.create())
                .baseUrl(Interactors.apiEndpoint)
                .build()
                .create(FriendsApiClient::class.java)


    }

给我一​​个

"Unable to create converter for class StickerDto"
Caused by NoJsonAdapter for java.util.Comparator<? super java.lang.String>

错误。如果不是那个 Moshi 转换器,我需要使用什么转换器?试图将它作为字符串拉下来也会产生错误,因为它是预期的和对象。我只需要那个字符串。

编辑,Json 字符串很长,但开头是这样的:

{"tileId":"1264373a-24d8-4c10-ae90-d6e8f671410c","friendId":"2c50f187-039a-4f85-b12b-0c802396a611","name":"David Carey","message":"Joined WeAre8","animatedSticker":{"v":"5.5.7","fr":24,"ip":0,"op":48,"w":1024,"h":1024,"nm":"party_popper","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"C | Position","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":45,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[176,892,0],"to":[-6.667,6.667,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":7,"s":[136,932,0],"to":[0,0,0],"ti":[-6.667,6.667,0]},{"t":11,"s":[176,892,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":7,"s":[115,75,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":11,"s":[95,105,100]},{"t":20,"s":[100,100,100]}],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Controller","np":13,"mn":"Pseudo/DUIK controller","ix":1,"en":1,"ef":[{"ty":6,"nm":"Icon","mn":"Pseudo/DUIK controller-0001","ix":1,"v":0},{"ty":2,"nm":"Color","mn":"Pseudo/DUIK controller-0002","ix":2,"v":{"a":0,"k":[0.92549020052,0.0941176489,0.0941176489,1],"ix":2}},{"ty":3,"nm":"Position","mn":"Pseudo/DUIK controller-0003","ix":3,"v":{"a":0,"k":[0,0],"ix":3}},{"ty":0,"nm":"Size","mn":"Pseudo/DUIK controller-0004","ix":4,"v":{"a":0,"k":100,"ix":4}},{"ty":0,"nm":"Orientation","mn":"Pseudo/DUIK controller-0005

【问题讨论】:

  • 我想你可以把这个val stickerData: JsonObject写成val stickerData: Map&lt;String, Any&gt;
  • 仍然从问题中得到错误 Caused by: java.lang.IllegalArgumentException: Platform class java.util.HashMap in java.util.HashMap需要显式注册 JsonAdapter
  • 你能分享一下儿子的sn-p吗? @andrewedgar
  • @andrewedgar 请发布一个sn-p
  • 我不明白,如果json有未知属性,那你要如何使用这些属性?!

标签: android retrofit2 moshi


【解决方案1】:

我将stickerData 做成了一个Map 并使用了GsonConverterFactory 而不是Moshi。

【讨论】:

  • 这仍然不能解决问题。它是一种解决方法。如果我们需要使用 Moshi 而不是 Gson 怎么办?
  • 是的,我会选择 gson,我必须为一个非常简单的对象 [ time: '2019-10-11...' , time : 123456 ] 做类似的事情,然后放弃并选择了 gson。对于需要简单适配器的简单对象,Moshi 非常麻烦。
【解决方案2】:

注意JsonObject是gson包中的一个类,所以如果你想使用Moshi你需要切换到JSONObject,这是Android支持的默认类。

为此,您需要编写自己的 JSONObject 适配器。

首先,编写你的适配器类:

import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.ToJson
import okio.Buffer
import org.json.JSONException
import org.json.JSONObject

class JSONObjectAdapter {
    
    @FromJson
    fun fromJson(reader: JsonReader): JSONObject? {
        // Here we're expecting the JSON object, it is processed as Map<String, Any> by Moshi
        return (reader.readJsonValue() as? Map<String, Any>)?.let { data ->
            try {
                JSONObject(data)
            } catch (e: JSONException) {
                // Handle exception
                return null
            }
        }
    }
    
    @ToJson
    fun toJson(writer: JsonWriter, value: JSONObject?) {
        value?.let { writer.value(Buffer().writeUtf8(value.toString())) }
    }
}

在创建 MoshiConverterFactory 时调整您的改造版本以提供自定义 Moshi 对象:

    .addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().add(JSONObjectAdapter()).build()))

然后你就可以开始使用 JSONObject了

@Json(name = "stickerData") val stickerData: JSONObject

祝你好运,我希望这会有所帮助!

【讨论】:

    【解决方案3】:

    Built-in Type Adapters for Moshi 包括数组、集合、列表、集合和映射JsonObject 类型不随 Moshi 本身提供,但无论如何它会是一个增强的Map&lt;String, Any&gt;,所以只需使用Map 而不是对象。

    @JsonClass(generateAdapter = true)
    class Sticker(
            @Json(name = "name") val name: String,
            @Json(name = "id") val id: String,
            @Json(name = "stickerData") val stickerData: Map<String, Any>,
            var isSelected: Boolean = false
    )
    

    这些值也会自动转换。因此,您会在那里找到字符串、列表或数字。

    【讨论】:

      猜你喜欢
      • 2021-05-20
      • 1970-01-01
      • 2021-02-03
      • 2018-03-28
      • 1970-01-01
      • 2018-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多