class GetBusinessMapResponseDTODeserializer : JsonDeserializer<GetBusinessMapResponseDTO> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): GetBusinessMapResponseDTO {
...
}
}
#Provides
#Singleton
fun provideRetrofit() : Retrofit {
val gsonBuilder = GsonBuilder()
.registerTypeAdapter(
GetBusinessMapResponseDTODeserializer::class.java,
GetBusinessMapResponseDTODeserializer())
.create()
val retrofit = Retrofit.Builder()
.baseUrl(IamHereBackendAPI.BASE_URL)
.addCallAdapterFactory(ResultAdapterFactory())
.addConverterFactory(GsonConverterFactory.create(gsonBuilder))
.build()
return retrofit
}
#POST("getAllBusinessesByFilterMap")
suspend fun getBusinessMapByFilter(
#Body getBusinessMapRequest: GetBusinessMapRequest
) : RequestResult<GetBusinessMapResponseDTO>
Hello! Can you please tell me why Gson does not want to use a custom deserializer? I thought the problem was that the response from the api was wrapped in the RequestResult class, but apparently this is not the problem
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
The problem is with your registerTypeAdapter call. The first argument is the class you want to register the adapter for. So instead of providing GetBusinessMapResponseDTODeserializer::class.java you should provide GetBusinessMapResponseDTO::class.java as argument:
val gsonBuilder = GsonBuilder()
.registerTypeAdapter(
GetBusinessMapResponseDTO::class.java,
GetBusinessMapResponseDTODeserializer())
.create()
Related
I'm receiving a response from BE and the response is a base64 encoded image. The response looks like this:
{"image":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/ ...} (whole response here: https://pastebin.com/ViFTAhRw)
Looks like a property named image followed by a string. So I've created my model class:
#JsonClass(generateAdapter = true)
data class ApiBase64Image(
#field:Json(name = "image") val imageString: String?
) {
fun toDomain(): Base64Image {
return Base64Image(imageString.orEmpty())
}
}
And finally, my DI object:
#Module
#InstallIn(SingletonComponent::class)
object ApiModule {
#Provides
#Singleton
fun provideApi(builder: Retrofit.Builder): MyApi {
return builder
.build()
.create(MyApi::class.java)
}
#Provides
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit.Builder {
return Retrofit.Builder()
.baseUrl(ApiConstants.BASE_ENDPOINT)
.client(okHttpClient)
.addConverterFactory(MoshiConverterFactory.create())
}
#Provides
fun provideOkHttpClient(
authenticationInterceptor: AuthenticationInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(authenticationInterceptor)
.build()
}
}
This code, however, does not work as I'm receiving errors:
Unable to create converter for class ... .ApiBase64Image
Failed to find the generated JsonAdapter class for class ... .ApiBase64Image
I'm not sure what is giving Moshi problems. Is it the data class serialization? Or my DI setup? Or something else entirely?
#JsonClass(generateAdapter = true)
This is used by Codegen, so you need to add that dependency :
plugins {
id("com.google.devtools.ksp").version("1.6.10-1.0.4") // Or latest version of KSP
}
dependencies {
ksp("com.squareup.moshi:moshi-kotlin-codegen:1.13.0")
}
interface ApiInterface {
#Headers("Content-Type: application/json")
#POST("testgetmemes/")
fun getMemes(): Call<List<Memes>>
}
object ApiClient {
var BASE_URL:String="https://www.blaaa.com/"
val getClient: ApiInterface
get() {
val gson = GsonBuilder()
.setLenient()
.create()
val client = OkHttpClient.Builder().build()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
return retrofit.create(ApiInterface::class.java)
}
}
and inside a function :
val call: Call<List<Memes>> = ApiClient.getClient.getMemes()
call.enqueue(object : Callback<List<Memes>> {
override fun onResponse(call: Call<List<Memes>>?, response: Response<List<Memes>>) {
Log.d(tagg, response!!.body()!!.toString())
//setMemes(response!!.body()!!, gal)
}
override fun onFailure(call: Call<List<Memes>>?, t: Throwable?) {
Log.d(tagg, t!!.toString())
}
})
I want to get the JSONArray instead of this ready to use Model List! Otherwise I would have to do a lot of changes and workarounds because I usually use beautiful loopj, this retrofit2 thing is only to make APIs work on older Android versions.
I tried that by replacing all <List<Memes>> with <JSONArray> but then I get this response:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
How to do this??
This is the way I do it now, using Gson:
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
..
JSONArray(Gson().toJson(response.body()))
No need to replace <List<Memes>> with <JSONArray>
I newbie on kotlin, its my firts app test. I trying to do a retrofit call (POST) but i get sintax error on create code.
My syntax error: no type arguments expected for CallBack
this is my doLogin function on presenter layer (i got error here):
override fun doLogin() {
val call = RetrofitInitializer().loginApiContract().login()
call.enqueue(object: Callback<UserAccount> {
override fun onResponse(call: Call<UserAccount>?,
response: Response<UserAccount) {
}
override fun onFailure(call: Call<UserAccount>?,
t: Throwable?) {
}
})
}
and that is my retrofit initializer:
class RetrofitInitializer {
private val retrofit = Retrofit.Builder()
.baseUrl("http://192.168.0.23:8080/")
.addConverterFactory(GsonConverterFactory.create())
.build()
fun loginApiContract() : LoginApiContract{
return retrofit.create(LoginApiContract::class.java)
}
}
that is my interface of call:
interface LoginApiContract {
#POST("login")
fun login() : Call<UserAccount>
#GET("statements")
fun getStatements()
}
Best practice with kotlin - use rxjava calladapter factory.
Try to add dependency
compile "com.squareup.retrofit2:adapter-rxjava2:"
and add call adapter factory
private val retrofit = Retrofit.Builder()
.baseUrl("http://192.168.0.23:8080/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
i want to provide a single gson instance, so i provide it in my NetworkModule, when i create retrofit api, gson is non null, but when i use gson instance in retrofit class, it is null..
#Module
class NetworkModule {
#Provides
#Singleton
fun provideGson(): Gson {
return Gson()
}
#Provides
#Singleton
fun provideMyEnterpriseApi(gson: Gson): MyEnterpriseApi {
//HERE GSON IS NOT NULL
return RetrofitMyEnterpriseApi(BuildConfig.API_MYENTERPRISE_URL,
BuildConfig.API_MYENTERPRISE_CONNECTION_TIMEOUT,
BuildConfig.API_MYENTERPRISE_READ_TIMEOUT,
gson)
}
}
My retrofit api class :
class RetrofitMyEnterpriseApi(baseUrl: String, connectTimeout: Long, readTimeout: Long, private val gson: Gson)
: RetrofitApi<RetrofitMyEnterpriseCalls>(baseUrl, connectTimeout, readTimeout, RetrofitMyEnterpriseCalls::class.java) {
override fun buildRetrofit(baseUrl: String, connectTimeout: Long, readTimeout: Long): Retrofit {
val builder = Retrofit.Builder()
builder.baseUrl(baseUrl)
builder.client(buildClient(connectTimeout, readTimeout))
builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
builder.addConverterFactory(GsonConverterFactory.create(gson))
return builder.build()
}
private fun buildClient(connectTimeout: Long, readTimeout: Long): OkHttpClient {
//HERE GSON IS NULL
return OkHttpClient.Builder()
.addInterceptor(OAuth2Interceptor(gson, this))
.addInterceptor(LoggingInterceptor.newInstance())
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.build()
}
}
RetrofitApi class:
abstract class RetrofitApi<C>
(baseUrl: String, connectTimeout: Long, readTimeout: Long, callsClass: Class<C>) {
protected val calls: C
init {
val retrofit = buildRetrofit(baseUrl, connectTimeout, readTimeout)
calls = retrofit.create(callsClass)
}
protected abstract fun buildRetrofit(baseUrl: String, connectTimeout: Long, readTimeout: Long): Retrofit
}
So, when i provide it's not null, but when i use it in buildClient method is null, i can't see why, i miss something in Kotlin maybe.
I found answer when i posted \o/
So the problem was gson field in RetrofitMyEnterpriseApi class is instancied after the init of RetrofitApi parent class, i think it's strange because i pass it in parameters but..
I just need to call my buildRetrofit method after init of RetrofitMyEnterpriseApi class, or send gson instance to my parent class.
Hi i get the following error:
java.lang.IllegalArgumentException: Unable to create #Body converter for class com.jr.app.models.ExampleData (parameter #1)
Here is my ExampleData.kt
data class ExampleData(val id: String,
val firstName: String,
val secondName: String,
val profilImages: String,
val info: String) {
}
My interface retrofit
interface UsersService {
#GET("/usersProfile")
fun getAllUsers(): Call<List<ExampleData>>
#POST("/usersProfile")
fun addUser(#Body exampleData: ExampleData): Call<ResponseBody>
}
function that addsUser
override fun addUser(user: ExampleData) {
val retrofit = Retrofit.Builder().baseUrl(baseUrl).client(httpAuthClient).build();
val userService = retrofit.create(UsersService::class.java);
userService.addUser(user).enqueue(callbackResponse);
}
private val httpAuthClient: OkHttpClient
get() {
val okHttpClient = OkHttpClient().newBuilder().addInterceptor { chain ->
val originalRequest = chain.request()
val builder = originalRequest.newBuilder().header(authorizeHeader,
Credentials.basic(userName, password))
val newRequest = builder.build()
chain.proceed(newRequest)
}.build()
return okHttpClient
}
Add the gradle dependency to your project:
compile 'com.squareup.retrofit2:converter-gson:VERSION_OF_RETROFIT'
When you build an instance of retrofit add this line:
.addConverterFactory(GsonConverterFactory.create())
In your project building the retrofit object will look like:
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(httpAuthClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
I believe this has nothing to do with Kotlin but your Retrofit configuration and your data class ExampleData.
Retrofit has no idea how to serialize your instance of ExampleData to JSON. You need to add a specific converter factory when creating instance of Retrofit client (see Builder#addConverterFactory method for details).