如何让我的 retrofit2 模型解析这个?

Posted

技术标签:

【中文标题】如何让我的 retrofit2 模型解析这个?【英文标题】:How to get my retrofit2 model to parse this? 【发布时间】:2021-11-08 11:16:27 【问题描述】:

这是异常的响应,其中对象的名称与对象的 ID 相同,此时我真的不知道如何解析此响应

"addresses": 
            "163492": 
                "address_id": "163492",
                //more of String variables
            ,
            "166127": 
                "address_id": "166127",
                //more of String variables
            ,
            "166202": 
                "address_id": "166202",
                //more of String variables
            
        

这就是我的事件模型的样子,我稍后会使用房间数据库来保存这个响应

@Entity
data class Event(
    @PrimaryKey(autoGenerate = false)
    @SerializedName("id") val id: Int,
    @SerializedName("title") val title: String,
    @SerializedName("description") val desc: String,
    @SerializedName("note") val note: String? = null,
    @SerializedName("date") val dateTs: Long,
    @SerializedName("begintime") val beginTime: String,
    @SerializedName("enddate") val endDate: String,
    @SerializedName("endtime") val endTime: String,
    @SerializedName("customerid") val customerId: String? = null,
    @SerializedName("address_id") val addressId: String? = null,
    @SerializedName("pin") val pin: String? = null,
    @SerializedName("location") val location: String? = null,
    @SerializedName("customerlocation") val customerLocation: String? = null,
    @field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
    @SerializedName("nodes") val nodes: List<Node>? = null,
    @SerializedName("closed") val closed: Int,
    @SerializedName("type") val type: Int,
    @SerializedName("ticketid") val ticketId: String? = null,
    @SerializedName("customername") val customerName: String? = null,
    @field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
    @SerializedName("contacts") val contacts: List<Contacts>? = null,
    @field:TypeConverters(beskidmedia.pl.scanner.room.TypeConverters::class)
    @SerializedName("addresses") val addresses: List<Address>? = null,
    @Embedded
    @SerializedName("assignments") val assignments: Assignments? = null,
    @SerializedName("lastUpdate") val lastUpdate: Long = System.currentTimeMillis()
)

地址部分之外的所有内容都很好,因为我使用带有 null 的地址的响应对其进行了测试,我尝试为此进行反序列化,但它似乎无法识别它,这就是它的样子

class EventDeserializer : JsonDeserializer<Event> 
    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): Event 
        json?.asJsonObject!!.let  event ->
            val nodes = mutableListOf<Node>()
            val contacts = mutableListOf<Contacts>()
            val addresses = mutableListOf<Address>()

            val net = mutableListOf<Assignment>()
            val tv = mutableListOf<Assignment>()
            val assignments = Assignments(net, tv)

            val netTemp = event.get("assignments").asJsonObject.get("assignments_net").asJsonArray
            val tvTemp = event.get("assignments").asJsonObject.get("assignments_tv").asJsonArray

            netTemp.forEach  assignment ->
                assignment.asJsonObject.let 
                    net.add(
                        Assignment(
                            name = it.get("name").asString,
                            id = it.get("id").asInt
                        )
                    )
                
            

            tvTemp.forEach  assignment ->
                assignment.asJsonObject.let 
                    tv.add(
                        Assignment(
                            name = it.get("name").asString,
                            id = it.get("id").asInt
                        )
                    )
                
            

            val nodesTemp = event.get("nodes").asJsonArray
            nodesTemp.forEach  node ->
                node.asJsonObject.let 
                    nodes.add(
                        Node(
                            id = it.get("id").asInt,
                            name = it.get("name").asString,
                            mac = it.get("mac").asString,
                            ip = it.get("ip").asString,
                            location = it.get("location").asString,
                            netName = it.get("netname").asString
                        )
                    )
                
            

            val contactsTemp = event.get("contacts").asJsonArray
            contactsTemp.forEach  contact ->
                contact.asJsonObject.let 
                    contacts.add(
                        Contacts(
                            phone = it.get("phone").asString,
                            contact = it.get("contact").asString,
                            name = it.get("name").asString,
                            type = it.get("type").asString,
                            typeStr = it.get("typestr").asString
                        )
                    )
                
            

            val addressesTemp = event.get("addresses").asJsonObject
            addressesTemp?.keySet()?.let  names ->
                names.forEach  name ->
                    addressesTemp.get(name).asJsonObject.let 
                        addresses.add(
                            Address(
                                id = it.get("address_id").asString,
                                name = it.get("location").asString
                            )
                        )
                    
                
            

            return Event(
                id = event.get("id").asInt,
                title = event.get("title").asString,
                desc = event.get("description").asString,
                note = event.get("note")?.asString,
                dateTs = event.get("date").asLong,
                beginTime = event.get("begintime").asString,
                endDate = event.get("enddate").asString,
                endTime = event.get("endtime").asString,
                customerId = event.get("customerid")?.asString,
                addressId = event.get("address_id")?.asString,
                pin = event.get("pin")?.asString,
                location = event.get("location")?.asString,
                customerLocation = event.get("customerlocation")?.asString,
                nodes = nodes,
                closed = event.get("closed").asInt,
                type = event.get("type").asInt,
                ticketId = event.get("ticketid")?.asString,
                customerName = event.get("customername")?.asString,
                contacts = contacts,
                addresses = addresses,
                assignments = assignments
            )
        


    

这就是我创建 gson 工厂的方式

val gson = GsonBuilder().registerTypeAdapter(Event::class.java, EventDeserializer())
Retrofit
                .Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(
                    GsonConverterFactory.create(gson.create())
                )
                .callbackExecutor(Executors.newSingleThreadExecutor())

响应的结构是这样的

Call<List<Event>>

但列表总是有 1 个元素,这是我无法更改的旧 api 的工件

【问题讨论】:

一个地址显然不是一个事件。您甚至在问什么都非常不清楚。此外,当使用转换器时,所有手动反序列化确实是完全无意义的。 地址是事件对象的一部分。我能够解决地址部分之外的所有问题,并且只有这部分响应是异常且难以解析的,这就是我需要帮助的地方。反序列化器方法失败了,但我将它包括在内只是为了展示我尝试过的内容。 【参考方案1】:

好的,所以我想通了,显然您的反序列化器需要与您的响应的类型完全相同,因此我添加了拦截器,该拦截器删除了包装每个响应的多余数组,现在反序列化器正在按预期使用。

【讨论】:

以上是关于如何让我的 retrofit2 模型解析这个?的主要内容,如果未能解决你的问题,请参考以下文章

如何让我的 Vigenère 密码处理消息中的空格?

Retrofit2

Retrofit2

Retrofit2

从retrofit2和rxjava中的错误获取url

如何使用Retrofit2 API在RecyclerView中显示数据?