Is this expression to get a nested array possible with Retrofit? - android

In a previous question some users commented as a response to access a nested array that this is possible:
fun getMovies(): Single<Response<List<Result>>>
But every time that I try to implement it it gives me the Error message:
No type arguments expected for class Response
This is my Model Class:
data class Response(
val page: Int?,
val total_results: Int?,
val total_pages: Int?,
val results: List<Result>
) {
//#Entity
data class Result(
val popularity: Double?,
val vote_count: Int?,
val video: Boolean?,
val poster_path: String?,
val id: Int?,
val adult: Boolean?,
val backdrop_path: String?,
val original_language: String?,
val original_title: String?,
val genre_ids: List<Int>?,
val title: String?,
val vote_average: Double?,
val overview: String?,
val release_date: String?
)
}
My Api Interface
package com.example.moviesapplication.model
import io.reactivex.Single
import retrofit2.http.GET
interface MoviesApi {
#GET("/3/discover/movie?api_key=${apiKey}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1")
fun getMovies(): Single<List<Response.Result>>
}
So if anyone know if the expression stated is possible or something similar, please let me know.

Your Response class doesn't have any generic parameters, and that's what the error is pointing out.
You can return Single<Response> and the array will always be a List of Result, it doesn't have any dynamic types.

I think you import wrong package, maybe you import Response of Okhttp instead of your Response data class since Response of OkHttp doesn't want type argument.
At the same time your Response is a bit strange, Your Response class does not want type argument. Your response should be something like
fun getMovies(): Single<Response>
instead of
fun getMovies(): Single<Response<List<Result>>>
I think it become like this because you confuse between Response of Retrofit that need type argument [Response<T>] and your Response data class that does not need type argument.
Recommend
I thinks it will be better if your Response class is some think like
data class Response<T>(
val page: Int?,
val total_results: Int?,
val total_pages: Int?,
val results: List<T> // or val results: T
)
Because if you have lots pf responses that have Base like Response class but, its result have different model or list (something likeList<ResultMovie> or List<...>). You only need to pass T to your Base model like Response<Result>. You not need to repeat to declare Response every time you have Base model like this, and it also easier to manage or fixes later.

Related

How to make a post method with data class + retrofit + moshi in kotlin?

I want to fill the data class with the data received from the user and pass it to the service with retrofit. The structure I set up is the mvvm structure and how can I adapt it to this structure,
The structure I have set up is as follows.
hear is my Data model code
RegisterLoginDataModel
#JsonClass(generateAdapter = true)
data class RegisterLoginDataModel(
#Json(name = "userGender")
var userGender: String?,
#Json(name = "userGoal")
var userGoal: String?,
#Json(name = "userTargetWeight")
var userTargetWeight: String?,
#Json(name = "userCurrentWeight")
var userCurrentWeight: String?,
#Json(name = "userTargetHeight")
var userTargetHeight: String?,
#Json(name = "userCurrentHeight")
var userCurrentHeight: String?,
#Json(name = "userBirthDay")
var userBirthDay: String?,
#Json(name = "userMail")
var userMail: String?,
#Json(name = "userName")
var userName: String?,
#Json(name = "userPassword")
var userPassword: String?
)
I have a data class that I will use for post in the data package. Can I access it directly from the ui or do I need to create a separate class for the domain and ui package, how can I do this? Could you help ?
In terms of architecture, it is better to build a model in the domain layer
which ends with Request.
Then give it to your network layer library ( in here retrofit ).
The operation of creating an instance of the model you created in the domain layer is also done in a place like UseCase

Kotlin android development diffutil itemCallback type error

Im trying to implement diffutil in my adapter and im getting the following error:
One type argument expected for class Result<out T>
This is the code where i get the error:
private val diffCallback = object: DiffUtil.ItemCallback<Result>() {
}
This is my Result class:
data class Result(
val adult: Boolean,
val backdrop_path: String,
val genre_ids: List<Int>,
val id: Int,
val media_type: String,
val original_language: String,
val original_title: String,
val overview: String,
val popularity: Double,
val poster_path: String,
val release_date: String,
val title: String,
val video: Boolean,
val vote_average: Double,
val vote_count: Int
)
I don't understand,this is exactly how i do this every time,and it works without problems
Kotlin already has a Result<T> type, and it's imported by default. You might need to fully qualify your own class name if you want to make sure you're using that one. Or maybe just rename your class, it will make things easier.

Serialize custom object list in a Response with kotlinx

I have the next json as response:
{"id":1581,"title":"hhhh","tags":[],"iconUrl":"images/b94cdcde-9c6c-4ea1-9c22-47b4c1750cce","valoration":0,"postList":[{"id":41,"x":0.58,"y":0.3,"rotation":338,"resourceUrl":"images/ba4202c2-845f-4b70-8167-5ef4ffb347bf","valoration":0}]}
And I have declared the response at my project as:
#Serializable
data class BoardResponse(
#SerialName("id")
val id: Int,
#SerialName("title")
val title: String,
#SerialName("tags")
val tags: List<String>,
#SerialName("iconUrl")
val iconUrl: String,
#SerialName("valoration")
val valoration: Float,
#SerialName("postList")
val posts: List<PostResponse>
)
The problem is that I'm getting allways a null in the "posts" value.
This is the PostResponse:
#Serializable
data class PostResponse(
#SerialName("id")
val id: Int,
#SerialName("x")
val x: Float,
#SerialName("y")
val y: Float,
#SerialName("rotation")
val rotation: Int,
#SerialName("resourceUrl")
val resourceUrl: String,
#SerialName("valoration")
val valoration: Float
)
Can I do what I'm trying to do in some way?
Your code is correct. With the exact same declarations as yours, and with the example JSON you provided, the following test passes (you get non-null posts):
#Test
fun test() {
val json = """{"id":1581,"title":"hhhh","tags":[],"iconUrl":"images/b94cdcde-9c6c-4ea1-9c22-47b4c1750cce","valoration":0,"postList":[{"id":41,"x":0.58,"y":0.3,"rotation":338,"resourceUrl":"images/ba4202c2-845f-4b70-8167-5ef4ffb347bf","valoration":0}]}"""
val resp = Json.decodeFromString<BoardResponse>(json)
assertEquals(1, resp.posts.size)
}
I believe something must be wrong in how you setup Kotlinx Serialization as deserialization library. Please update your question with more details about how you use the library to deserialize this JSON, or open another question.
data class PostResponse(
val id: Int,
val x: Float,
val y: Float,
val rotation: Int,
val resourceUrl: String,
val valoration: Float
) : Serializable
Note: All variables names must be same as your response parameters(key)
Forget it, the only problem was the name of the val:
val posts: List
Just changed that to postList and it worked. No idea that the val name could be linked to the json name.

How to check if an object has a certain property

I have two distinct classes:
internal data class ClassB(
#Json(name = "id") val id: String?,
#Json(name = "name") val name: String?,
#Json(name = "url") var contentUrl: String?,
#Json(name = "mediaImageUri") val coverUrl: String?,
#Json(name = "mediaVideoCoverImageUri") val videoCoverUrl: String?
)
internal data class ClassC(
#Json(name = "tileId") val id: String?,
#Json(name = "friendId") val friendId: String?,
#Json(name = "profilePictureUri") var profilePicture: String?,
#Json(name = "name") var name: String?
)
That inherit from the same class:
internal open class ClassA(
#Json(name ="type") var type: String?,
#Json(name ="sponsor-offer") var offer: SponsorOffer?,
#Json(name ="date") var date: Date?,
#Json(name ="weight") var priorityWeight: Int?
)
I am using an API call that returns a list of ClassA and is parsed by retrofit into a List, and need to cast each object onto one of the child classes before adding it to a local ArrayList<Any>
I am attempting to do this by iterating through the list returned and checking for the proprietary attributes of Classes B and C. then casting to object to the appropriate one before adding it to a local array. How can I check for these attributes? Is there a better way to do what I am attempting to do?
classA.javaClass.kotlin.members.any is not working
If ClassB and ClassC both extend ClassA, then you can just use the is keyword to check the type and then cast it
val thing: ClassA = getThing()
if (thing is ClassB) {
// thing should have been smart-cast to ClassB in here, or you can:
val thingB = thing as ClassB
}
or you could use a when block to check the possible types.
Or you can use the safe-cast operator as?, which evaluates to null if you can't cast to that type:
(thing as? ClassB)?.let { ... } ?: // it was null, so it's not ClassB, so...
But if you're doing this to put them into an ArrayList<Any> then there's no point casting them, that information is lost - it's a list of Anys! You'll have to recheck the type and cast each item when you take them out.
If you want to hold separate lists of ArrayList<ClassB> and ArrayList<ClassC>, then casting so you can put them in the right list (which will only accept that type) is ok - you'll know exactly what you're getting out of those

Using default JsonDeserializer inside custom JsonDeserializer in Kotlin

I'm trying to build custom deserializers for the responses I get from OMDb API.
Here's the data class for Movie:
data class Movie(
val title: String?,
val year: String?,
val imdbID: String?,
val type: String?,
val poster: String?,
val mpaRating: String?,
val runtime: String?,
val genres: String?,
val director: String?,
val writers: List<String>?,
val actors: List<String>?,
val plot: String?,
val awards: String?,
val boxOfficeEarnings: String?,
val ratings: List<Rating>,
val response: Boolean?
)
And for Rating:
data class Rating(
#SerializedName("Source")
val source: String,
#SerializedName("Value")
val value: String
)
This is the custom JsonDeserializer so far:
class MovieDeserializer : JsonDeserializer<Movie>
{
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Movie
{
val movieJsonObject = json?.asJsonObject
return Movie(
movieJsonObject?.get("Title")?.asString,
movieJsonObject?.get("Year")?.asString,
movieJsonObject?.get("imdbID")?.asString,
movieJsonObject?.get("Type")?.asString,
movieJsonObject?.get("Poster")?.asString,
movieJsonObject?.get("Rated")?.asString,
movieJsonObject?.get("Runtime")?.asString,
movieJsonObject?.get("Genre")?.asString,
movieJsonObject?.get("Director")?.asString,
separateStringByComma(movieJsonObject?.get("Writer")?.asString),
separateStringByComma(movieJsonObject?.get("Actors")?.asString),
movieJsonObject?.get("Plot")?.asString,
movieJsonObject?.get("Awards")?.asString,
movieJsonObject?.get("BoxOffice")?.asString,
// this is where I need help,
movieJsonObject?.get("Response")?.asBoolean
)
}
fun separateStringByComma(stringToSeparate: String?): List<String>?
{
return stringToSeparate?.split(", ")
}
}
How can I convert that JsonElement directly to List<Rating> without some json string manipulation?
By the way, I'm using Retrofit with Gson:
val gsonMovieDeserializer = GsonBuilder()
.registerTypeAdapter(Movie::class.java, MovieDeserializer())
.create()
val retrofit = Retrofit.Builder()
.baseUrl("https://www.omdbapi.com/")
.addConverterFactory(GsonConverterFactory.create(gsonMovieDeserializer))
.build()
val omdbApi = retrofit.create(OmdbApi::class.java)
val movie = omdbApi.getMovie(movieImdbId.value.toString())
First of all, I'd like to point the usage of nullables there: instead of checking wheter movieJsonObject is null or not for every call inside deserialize(), you should change the function parameters not to be null and then check only once, right at the beggining, if json is a JsonObject, just skipping everything if it's not. That way, we have a solid base to extract the data. Also, for the Movie data class, check the API documentation for which fields are optional and only set those to nulalble (I'm pretty sure at least the title and ID there are always present, so it's way more useful to have them as non-nullable).
Now, for the question itself, you should probably be able to deserialize that list using context.deserialize<List<Rating>>(movieJsonObject.get("Ratings"), List::class.java), which, in Kotlin, will return a type-safe List<Rating> (but, again, make sure that's not an optional field in the API and, if it is, make it nullable).

Categories

Resources