Make Kotlin Serializer work with Retrofit

Viewed 9989

I cant make Kotlin Serializer work with Retrofit. I am using com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.5.0 package along with Retrofit.

data classes

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable


@Serializable
data class YelpSearchResult(
    @SerialName("total") val total: Int,
    @SerialName("businesses") val restaurants: List<YelpRestaurant>
)

data class YelpRestaurant(
    val name: String,
    val rating: Double,
    val price: String,
    @SerialName("review_count") val numReviews: Int,
    @SerialName("distance") val distanceInMeters: Double,
    @SerialName("image_url") val imageUrl: String,
    val categories: List<YelpCategory>,
    val location: YelpLocation
) {

    fun displayDistance(): String {
        val milesPerMeter = 0.000621371
        val distanceInMiles = "%.2f".format(distanceInMeters * milesPerMeter)
        return "$distanceInMiles mi"
    }
}

data class YelpCategory(
    val title: String
)

data class YelpLocation(
    @SerialName("address1") val address: String
)

service interface

public interface YelpService {
    @GET("businesses/search")
    fun searchRestaurants(
        @Header("Authorization") authHeader: String,
        @Query("term") searchTerm: String,
        @Query("location") location: String): Call<YelpSearchResult>
}

The Activity

    val contentType = MediaType.get("application/json")
    val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(Json.asConverterFactory(contentType))
            .build()

    val yelpService = retrofit.create(YelpService::class.java)


    yelpService.searchRestaurants("Bearer ${api_key}",
        "Something", "Some Location").enqueue(
            object: Callback<YelpSearchResult> {
                override fun onFailure(call: Call<YelpSearchResult>, t: Throwable) {
                    Log.d("MainActivity", "err ${t}")

                }
                override fun onResponse(call: Call<YelpSearchResult>, response: Response<YelpSearchResult>) {
                    Log.d("MainActivity", "succ ${response}")
                }
            }
    )

When Running, the thrown exception is,

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xx.xx/com.xx.xx.MainActivity}: java.lang.IllegalArgumentException: Unable to create converter for class com.xx.xx.YelpSearchResult

Unable to create converter for class com.xx.xx.YelpSearchResult for method YelpService.searchRestaurants

Caused by: kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class YelpSearchResult. For generic classes, such as lists, please provide serializer explicitly.

What am I doing wrong? thanks for any directions.

2 Answers

You forgot to put @Serializable annotation on top of YelpRestaurant

@Serializable
data class YelpRestaurant {
...
}

YellCategory and YelpLocation should also have the annotation at place.

Add Serializable in your data classes

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable


@Serializable
data class YelpSearchResult(
    @SerialName("total") val total: Int,
    @SerialName("businesses") val restaurants: List<YelpRestaurant>
)

@Serializable
data class YelpRestaurant(
    val name: String,
    val rating: Double,
    val price: String,
    @SerialName("review_count") val numReviews: Int,
    @SerialName("distance") val distanceInMeters: Double,
    @SerialName("image_url") val imageUrl: String,
    val categories: List<YelpCategory>,
    val location: YelpLocation
) {

    fun displayDistance(): String {
        val milesPerMeter = 0.000621371
        val distanceInMiles = "%.2f".format(distanceInMeters * milesPerMeter)
        return "$distanceInMiles mi"
    }
}

@Serializable
data class YelpCategory(
    val title: String
)

@Serializable
data class YelpLocation(
    @SerialName("address1") val address: String
)
Related