Serialize custom object list in a Response with kotlinx - android

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.

Related

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.

Why needn't the object add #Parcelize when I try to store state?

I'm learning Compose by the article.
The article tell me:
All data types that are added to the Bundle are saved automatically. The simplest solution is to add the #Parcelize annotation to the object.
And it gives me the sample code.
#Parcelize
data class City(val name: String, val country: String) : Parcelable
#Composable
fun CityScreen() {
var selectedCity = rememberSaveable {
mutableStateOf(City("Madrid", "Spain"))
}
}
The following code is from the project.
I find the data class Post doesn't add #Parcelize, and val featured = remember { PostRepo.getFeaturedPost() } is OK, why?
#Composable
fun Home() {
val featured = remember { PostRepo.getFeaturedPost() }
val posts = remember { PostRepo.getPosts() }
...
}
object PostRepo {
fun getPosts(): List<Post> = posts
fun getFeaturedPost(): Post = posts.random()
}
#Immutable
data class Post(
val id: Long,
val title: String,
val subtitle: String? = null,
val url: String,
val metadata: Metadata,
#DrawableRes val imageId: Int,
#DrawableRes val imageThumbId: Int,
val tags: Set<String>
)
#Immutable
data class Metadata(
val author: PostAuthor,
val date: String,
val readTimeMinutes: Int
)
#Immutable
data class PostAuthor(
val name: String,
val url: String? = null
)
While remember helps you retain state across recompositions, the state is not retained across configuration changes. For this, you use rememberSaveable. RememberSaveable automatically saves any value that can be saved in a Bundle. For other values, you can pass in a custom saver object.
Since RememberSaveable automatically saves any value that can be saved in a Bundle , it requires the class to be Parcelable unlike remember .

How to parse json in android

https://api.mojilala.com/v1/stickers/trending?api_key=dc6zaTOxFJmzC
data class RootApi(val data : List<AllData>)
data class AllData(val images : ImageSticker)
data class ImageSticker(val fixed_height : ActualImage)
data class ActualImage(val url : String)
is this the correct POJO class or not according to given api
Firstly, hide your API key in the question. Coming to generating data classes of JSON. I would suggest you use the following Plugin
https://plugins.jetbrains.com/plugin/9960-json-to-kotlin-class-jsontokotlinclass-
And no that is not the correct data class. Infact it is very big. I can't even paste it all in the answer. Use the plugin. Paste the JSON response and generate yourself.
Following the answer from #che10 you should end up with the below:
data class Data(
// Assuming you are using Moshi https://github.com/square/moshi
// Use #SerializedName("data") if you're using Gson
#Json(name="data")
val stickers: List<Sticker>,
val meta: Meta,
val pagination: Pagination
)
data class Sticker(
val designer: String,
val id: String,
val images: Images,
val is_animated: Boolean,
val rating: String,
val tags: List<String>,
val url: String
)
data class Pagination(
val offset: String,
val total: Int,
val total_count: Int
)
data class Meta(
val msg: String,
val status: Int
)
// Different fields but of two types so we can reuse the classes
// Difference between AnimatedImage and StillImage is the two webp fields
data class Images(
// Animated images
val fixed_height: AnimatedImage,
val fixed_height_downsampled: AnimatedImage,
val fixed_height_medium: AnimatedImage,
val fixed_height_medium_downsampled: AnimatedImage,
val fixed_height_small: AnimatedImage,
val fixed_width: AnimatedImage,
val fixed_width_downsampled: AnimatedImage,
val fixed_width_medium: AnimatedImage,
val fixed_width_medium_downsampled: AnimatedImage,
val fixed_width_small: AnimatedImage,
// Still images
val fixed_height_still: StillImage,
val fixed_height_medium_still: StillImage,
val fixed_height_small_still: StillImage,
val fixed_width_still: StillImage,
val fixed_width_medium_still: StillImage,
val fixed_width_small_still: StillImage,
)
data class StillImage(
val url: String,
val size: Int,
val height: Int,
val width: Int,
)
data class AnimatedImage(
val url: String,
val size: Int,
val height: Int,
val width: Int,
val webp: String,
val webp_size: Int
)

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

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.

Delete empty arrays in Gson

I read topics like Android GSON deserialize delete empty arrays, https://medium.com/#int02h/custom-deserialization-with-gson-1bab538c0bfa, How do you get GSON to omit null or empty objects and empty arrays and lists?.
For instance, I have a class:
data class ViewProfileResponse(
val success: Int,
val wallets: List<Wallet>?,
val contact: Contact?,
val code: Int,
val errors: ErrorsResponse?
) {
data class Contact(
val countryId: Int,
val regionId: Int,
val cityId: Int
)
data class Wallet(
val id: Int,
val currency: String?,
val createTime: Int,
val balance: Float,
val bonusWallet: BonusWallet?
) {
data class BonusWallet(val id: Int, val balance: Float)
}
data class ErrorsResponse(val common: List<String>?)
class Deserializer : ResponseDeserializable<ViewProfileResponse> {
override fun deserialize(content: String): ViewProfileResponse? =
Gson().fromJson(content, ViewProfileResponse::class.java)
}
}
As you see, I have a complex class with subclasses, any of each can be null. But instead of sending null or {} in these fields, a server sends [] in JSON.
I mean, instead of "contact": null I get "contact": [].
How to write a custom deserializer for Gson? So that empty arrays could be removed, but other types retain. I have tens of those classes.
A temporary solution is based on https://stackoverflow.com/a/54709501/2914140.
In this case Deserializer will look like:
class Deserializer : ResponseDeserializable<ViewProfileResponse> {
private val gson = Gson()
private val gsonConverter = GsonConverter()
override fun deserialize(content: String): ViewProfileResponse? =
gson.fromJson(gsonConverter.cleanJson(content), ViewProfileResponse::class.java)
}

Categories

Resources