0x29a
0x29a

Reputation: 773

Unable to invoke no-args constructor for retrofit2.Call

I have the following retrofit singleton:

interface MyAPI
{
    @GET("/data.json")
    suspend fun fetchData() : Call<MyResponse>

    companion object
    {
        private val BASE_URL = "http://10.0.2.2:8080/"

        fun create(): MyAPI
        {
            val gson = GsonBuilder()
                .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                .create()

            val retrofit = Retrofit.Builder()
                .addConverterFactory( GsonConverterFactory.create( gson ) )
                .baseUrl( BASE_URL )
                .build()

            return retrofit.create( MyAPI::class.java )
        }
    }
}

MyResponse.kt

data class MyResponse(
    val listOfData: List<DataEntity>
)

DataEntity.kt

data class DataEntity(
    @SerializedName("name")
    val fullName: String
}

I call the code from ModelView the following way:

viewModelScope.launch {
    try {
        val webResponse = MyAPI.create().fetchData().await()
        Log.d( tag, webResponse.toString() )
    }
    catch ( e : Exception )
    {
        Log.d( tag, "Exception: " + e.message )
    }
}

But I keep getting:

Unable to invoke no-args constructor for retrofit2.Call<com.host.myproject.net.response.MyResponse>. Registering an InstanceCreator with Gson for this type may fix this problem.

I can't seem to find a solution for this problem.. Any hints please?

EDIT:

The JSON response:

[
    {
    "name": "A"
    },
    {
    "name": "B"
    },
    {
    "name": "C"
    }
]

Upvotes: 22

Views: 17879

Answers (5)

Enselic
Enselic

Reputation: 4912

The problem is that you try to combine suspend with a Call<T> return type. When you use suspend you should make the Retrofit function return the data directly, like this:

suspend fun fetchData() : List<DataEntity> // Note: Not MyResponse, see below

Then all you have to do is to remove .await() when you make the call, like this:

// Will throw exception unless HTTP 2xx is returned
val webResponse = MyAPI.create().fetchData()

Note that you should not use the MyResponse class at all since the JSON returns an array directly.

Update:

You can also use Response<DataEntity> if you need the info from headers

Upvotes: 60

Jakha
Jakha

Reputation: 11

if you are using suspend fuction, just remove it

  @GET("v1/clients/{client_id}/promocode-info/")
    suspend fun getPromoCodeInfo(
        @Path("client_id") clientId: String,
        @Query("promocode") promoCodeName: String,
    ): PromoCodeResponse


    @GET("v1/clients/{client_id}/promocode-info/")
    fun getPromoCodeInfo(
        @Path("client_id") clientId: String,
        @Query("promocode") promoCodeName: String,
    ): PromoCodeResponse

Upvotes: 0

I have same issue, after checking my model is fine. Then I try to remove suspend on interface API.

@GET("/data.json")
suspend fun fetchData() : Call<MyResponse>

To be

@GET("/data.json")
fun fetchData() : Call<MyResponse>

It solved (the error Unable to invoke no-args constructor for retrofit2.Call has gone).

Upvotes: 7

Ahsan Ullah Rasel
Ahsan Ullah Rasel

Reputation: 951

In addition with @Enselic's answer, if you want to get response (for error handling etc.) you can return Response<T> class of Retrofit2 instead of returning data directly. For example,

@POST("/api/news")
@CheckResult
suspend fun getNewsList(
    @Body newsRequest: NewsRequest
): Response<NewsResponse>

Upvotes: 2

creativecoder
creativecoder

Reputation: 1540

Step 1: Remove call and handle the response

Before:

@POST("list")
    suspend fun requestList(@Body body: JsonObject): call<Profile>

After

@POST("list")
    suspend fun requestList(@Body body: JsonObject): Profile

step 2:Remove suspend and handle the response

 @POST("list")
     fun requestList(@Body body: JsonObject): call<Profile>

Upvotes: 9

Related Questions