Android Kotlin - retrofit2 get JSONArray instead Model List - android

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>

Related

Retrofit + Gson. Gson not calling custom deserializer

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()

Add Multiple #Path with retrofit call

I have an api request where in the url i need to pass multiple #Path and i did so but i keep getting an error , i would like to get some help with this issue , thank you in advance
This is sample of url
https://api.site.dev/api/v2/entries/en_US/hello
This is the retrofit setup
#Singleton
#Provides
fun provideRetrofitInstance(): ApiInterface {
val httpLoggingInterceptor = HttpLoggingInterceptor()
val interceptor = httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC)
val okHttp = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
return Retrofit.Builder()
.baseUrl("https://api.site.dev/api/v2/entries/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttp)
.build()
.create(ApiInterface::class.java)
}
This is my retrofit Call
Error Unable to create call adapter for class com.dic.mydictionnary.models.DictionnaryModelItem
for method ApiInterface.getDictionnaryWord
*This is my apiInterfac
#GET("{language_code}/{word}")
fun getDictionnaryWord(
#Path("language_code") language : String,
#Path("word") word : String,
) : DictionnaryModelItem
}
It looks like Retrofit is trying to find a way of creating a DictionnaryModelItem for your service interface. You need to change that to this:
#GET("{language_code}/{word}")
suspend fun getDictionnaryWord(
#Path("language_code") language : String,
#Path("word") word : String,
) : Response<DictionnaryModelItem>

Android make POST request with retrofit

I'm trying to make my first POST request to make the user login using retrofit library, but it's not working and i don't understand why. If i make a GET request it works, but with POST something gone wrong and i don't understand why. My API run on localhost webserver
My code of the LoginService:
private const val BASE_URL = "http://localhost:10000/api/"
/**
* Build the Moshi object that Retrofit will be using, making sure to add the Kotlin adapter for
* full Kotlin compatibility.
*/
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
/**
* Use the Retrofit builder to build a retrofit object using a Moshi converter with our Moshi
* object.
*/
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.build()
interface LoginApiService {
#Headers("Content-Type: application/json")
#POST("login")
suspend fun makeLogin(#Body usr: User): LoginResponse
}
/**
* A public Api object that exposes the lazy-initialized Retrofit service
*/
object LoginApi {
val retrofitService : LoginApiService by lazy { retrofit.create(LoginApiService::class.java) }
}
code of the LoginResponse class
data class LoginResponse(
val token: String,
val expiration: Date,
val role: Int)
code of the User class:
data class User(
val mail: String,
val pw: String
) : Parcelable
Code of the ViewModel that make the request:
private fun makeLogin(email: String, password: String) {
viewModelScope.launch {
try {
val usr = User(email, password)
val rsp = LoginApi.retrofitService.makeLogin(usr)
_isLogged.value = true
} catch (ex: Exception) {
_status.value = LoginStatus.ERROR
}
}
}
Can someone help me to solve this please? it seems that the request it's not sended.
my retrofit call generate this error in logcat in the try-catch block
java.lang.IllegalArgumentException: Unable to create converter for class com.example.ticketapp.network.LoginResponse
for method LoginApiService.makeLogin
Default Retrofit's timeout is 10sec. You can fix it like this:
val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
...
.client(client)
.build()
Here I set it to 30secs, but you can use any number and TimeUnit you want.
UPD:
You can store Retorfit builder in a separate file like this:
interface WebService {
companion object {
fun <T> build(clazz: Class<T>): T {
val client = OkHttpClient.Builder()
...
.build()
val retrofit = Retrofit.Builder()
...
.build()
return retrofit.create(clazz)
}
}
}
Then you can have multiple ApiService interfaces. And use them like this:
val myApiService = WebService.build(MyApiServiceInterface::class.java)
myApiService.myRequestFunction()
Try to add
android:usesCleartextTraffic="true"
Into your application tag in manifest

Problems on call retrofit

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()

Retrofit with kotlin, unable to create #Body

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).

Categories

Resources