简体   繁体   中英

Retrofit2, how I can convert response with diferent object names but same data types

I have one call that return different objects name, in this case, each name is the hash of your wallet address, but I would like to treat them indifferently because all that matters is the data that is inside them, using a standard converter like Gson I am not able to do this, is there any way to do it manually?

{
"0x1234": {
    "success": true,
    "cache_last_updated": 1642815869695,
    "total": 500
},
"0x1244445": {
    "success": true,
    "cache_last_updated": 1642815869695,
    "total": 324
},
"0x47851":{
    "success": true,
    "cache_last_updated": 1642815869695,
    "total": 324
}
}

My Repository:

class WalletsResumeRepository(
private val service: apiService
) {
suspend fun getAddressData(listAddress: List<String>): Flow<Result<List<DetailModel>>> =
    flow {
        emit(Result.success(service.getWalletResume(listAddress))
    }.catch { e ->
        emit(Result.failure(RuntimeException("Something went wrong ${e.cause}")))
    }
   }

my repository always falls into the catch scenario with an NPE, remembering that the response can have countless addresses so infinite object names, how can I treat them as generics and map only the responses as lists? or something like that?

Service.kt

suspend fun getWalletResume(@Path("address") wallet: String): WalletDetailDTO

WalletDTO

data class WalletDetailDTO(
    val success: Boolean,
    @SerializedName("cache_last_updated")
    val cacheLastUpdated: Long?,
    val totalSlp: Int?
)

As I understand your question, this less to do with retrofit and more with JSON parsing. Because the payload structure is a bit awkward I suggest you consume it in two steps:

  • step 1. Consume the content success , cache_last_updated and total
  • step 2. Add the id
data class DetailModel(val id: String = "", val success: Boolean, val cache_last_updated: Long, val total: Int) 

interface apiService {
    @GET("....")
    fun getWalletResume( listAddress: List<String> ): Call<Map<String, DetailModel>>
}

The result of calling apiService.getWalletResume is Map<String, DetailModel> which you then process in step 2.

Example

val json = """
    {
      "0x1234": {
        "success": true,
        "cache_last_updated": 1642815869695,
        "total": 500
      },
      "0x1244445": {
        "success": true,
        "cache_last_updated": 1642815869695,
        "total": 324
      },
      "0x47851": {
        "success": true,
        "cache_last_updated": 1642815869695,
        "total": 324
      }
    }
""".trimIndent()


data class DetailModel(val id: String = "", val success: Boolean, val cache_last_updated: Long, val total: Int)

fun main() {
    val gson = Gson()
    val type: Type = object : TypeToken<Map<String, DetailModel>?>() {}.type
    val mapResult: Map<String, DetailModel> = gson.fromJson(json, type)

    // step 2
    val result = mapResult.map { entry -> entry.value.copy(id = entry.key) }

    println(result) 
    // [DetailModel(id=0x1234, success=true, cache_last_updated=1642815869695, total=500), DetailModel(id=0x1244445, success=true, cache_last_updated=1642815869695, total=324), DetailModel(id=0x47851, success=true, cache_last_updated=1642815869695, total=324)]
}

It sounds to me like you are just looking for a response type of Map<String, WalletData> . Then you can simply look at the "values" in the map to get a unique list of objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM