Can't parse json correctly - android

need help in parsing this json file from this endpoint
http://ergast.com/api/f1/constructors
this is my data class
data class Teams(
val MRData: MRdata
){
data class MRdata(
val ConstructorTable: ConstructorsTable,
val limit: String,
val offset: String,
val series: String,
val total: String,
val url: String,
val xmlns: String
){
data class ConstructorsTable(
val Constructors: List<Constructor>?
) {
data class Constructor(
val constructorId: String?,
val name: String?,
val nationality: String?,
val url: String?
)
}
}
}
when i use Teams class as a return model it logs actual data but, when i try to return specific data like constructorID or nationality it returns null.

Related

How to make post request with retrofit + moshi

I'm trying to make a post with retrofit and moshi but keep getting the error mess
com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was STRING at path $
I can't seem to understand why this is so. This is a sample of the json tested on postman:
{
"customerName": "Name",
"customerPhoneNo": "090000000",
"customerAddress": "Address",
"note": "Please",
"items" : [{
"productUid": "5633e1f1-8b00-46de-b73e-43799245a4e8",
"quantity" : "3"
},{
"ProductUid": "fca3ffb1-0130-4e47-b499-721d046c1e32",
"Quantity" : "5"
},
{
"ProductUid": "6a7f3e24-03ff-408a-b67e-8530d411390c",
"Quantity" : "2"
}]
}
My data classes are set up like so:
#Parcelize
data class Order(
val items: List<Item>?,
val customerName: String,
val customerPhoneNo: String,
val customerAddress: String,
val note: String
) : Parcelable
and
#Parcelize
data class Item(
val productUid: String,
var quantity: Int
) : Parcelable
Service utils look like:
interface ProductService {
#Headers("Content-Type: application/json")
#POST("/api/order/saveorder")
suspend fun postProds(#Body order: Order
): Response<Order>
#GET("/api/product/allproducts")
suspend fun getProds(): Response<List<ProdsItem>>
}
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
object Network {
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi)
.asLenient()
)
.build()
object ProdsApi {
val retrofitService: ProductService by lazy {
retrofit.create(ProductService::class.java)
}
}
}
The sendOrder function is set up like so:
suspend fun sendOrder(order: Order) {
withContext(Dispatchers.Main){
try {
val orderResponse = Network.ProdsApi.retrofitService.postProds(
order )
}
catch (e: Exception) {
Timber.e(e)
}
}
}
The GET request works perfectly.
Any help on this would be appreciated please.
In your Item Data Class you are using quantity as an Int but if you see the Postman JSON response it is a String.
So your class should be like:
data class Item(
#Json(name = "productUid")
val productUid: String?,
#Json(name = "quantity")
var quantity: String
)
Also as I see the key in your JSON response are written in two different ways.
For example your "Product ID" is written as "productUid" in one of the object and is written as "ProductUid" in another object.
So your complete Item Data Class should more look like this :
data class Item(
#Json(name = "productUid")
val productUid: String?,
#Json(name = "ProductUid")
val productUid: String?,
#Json(name = "quantity")
val quantity: String?,
#Json(name = "Quantity")
val quantity: String?
)
Add to app/build.gradle
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
Refactor your data class
check the key in your item and replace with right one
if productUid or ProductUid
quantity or Quantity
#JsonClass(generateAdapter = true)
data class Item(
#Json(name = "productUid")
val productUid: String,
#Json(name = "quantity")
var quantity: String
)
#JsonClass(generateAdapter = true)
data class Order(
#Json(name = "items")
val items: List<Item>,
#Json(name = "customerName")
val customerName: String,
#Json(name = "customerPhoneNo")
val customerPhoneNo: String,
#Json(name = "customerAddress")
val customerAddress: String,
#Json(name = "note")
val note: String
)
and try it again

Parameter specified as non-null is null error in Room Database

Here is my entity class:
#Entity
data class User(
#PrimaryKey
#Json(name = "id") val userId: String,
#Json(name = "login") val userName: String,
#Json(name = "avatar_url") val userAvatar: String,
val profile: Profile? = null
) : Serializable
Here is my Profile data class
data class Profile(
val avatar_url: String,
val bio: String,
val blog: String,
val company: Any,
val created_at: String,
val email: Any,
val events_url: String,
val followers: Int,
val followers_url: String,
val following: Int,
val following_url: String,
val gists_url: String,
val gravatar_id: String,
val hireable: Boolean,
val html_url: String,
val id: Int,
val location: String,
val login: String,
val name: String,
val node_id: String,
val organizations_url: String,
val public_gists: Int,
val public_repos: Int,
val received_events_url: String,
val repos_url: String,
val site_admin: Boolean,
val starred_url: String,
val subscriptions_url: String,
val twitter_username: Any,
val type: String,
val updated_at: String,
val url: String
) : Serializable
but every time I try to insert data into the table I am getting the error, how can I insert null data object in table while using room database?
The issue here is that Room doesn't know how to insert attribute of type Profile to the table.
The simple solution would be to use a type converter. Something like the following:
class DatabaseConverters {
#TypeConverter
fun toProfile(profileJson: String): Profile? {
return <Create a Profile object out of a JSON string>
}
#TypeConverter
fun fromProfile(profile: Profile?): String {
return <JSON string representation of Profile object>
}
}
In your case - you can use "" (empty string) when Profile is null.
More info about converters: Here

Android Room: Entities and POJOs must have a usable public constructor

I'm trying to save the data class i got from json to room database and suddenly get errors like this while building the app.
Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
NewsResponse model object
data class NewsResponse(
val copyright: String,
val response: Response,
val status: String
)
Response object
data class Response(
val docs: List<Docs>
)
Docs object(this is the data class i want to save)
#Entity(
tableName = "docs"
)
data class Docs(
#PrimaryKey(autoGenerate = true)
var id: Int? = null,
val _id: String,
val `abstract`: String,
#Embedded
val byline: Byline,
val document_type: String,
#Embedded
val multimedia: Multimedia,
#Embedded
val headline: Headline,
val lead_paragraph: String,
val news_desk: String,
val pub_date: String,
val section_name: String,
val snippet: String,
val source: String,
val subsection_name: String,
val type_of_material: String,
val uri: String,
val web_url: String,
val word_count: Int
)
Byline object
#Entity
data class Byline(
val original: String
)
Multimedia object
#Entity
data class Multimedia(
val url: String
)
Headline object
#Entity
data class Headline(
val main: String
)
Any ideas how to solve this?

Data Class and properties from other Data Class

I'm downloading few lists (RawAlbum, RawPhoto) from the web and I want to use properties from them to create another list. Then I want to use it to make a recyclerview.
So that's how it looks. It is the ListItem:
#Parcelize
data class ListItem(
val id: Int,
val title: String,
val albumTitle: String,
val thumbnailUrl: String
) : Parcelable
So I want to use the id and title from the RawAlbum. While the albumTitle and thumbnailUrl from the RawPhoto.
RawAlbum:
#Parcelize
#Entity(tableName = "albums")
data class RawAlbum(
#PrimaryKey
val id: Int,
val userId: Int,
val title: String
) : Parcelable
RawPhoto:
#Parcelize
#Entity(tableName = "photos")
data class RawPhoto(
#PrimaryKey
val id: Int,
val albumId: Int,
val title: String,
val url: String,
val thumbnailUrl: String
) : Parcelable

getting weather results from json (kotlin android)

I'm trying to get some results from json but i have a problem.When i have only this line of code it works and i can get the temperature
var main: TemperatureData? = null
but i want also to get more values from my json so i insert this line of code
var weather: WeatherDataJson? = null
When i'm adding the second line it doesn't fetch any data(it even stops fetching the var main:... data)
This is my weather data class
class WeatherData {
var main: TemperatureData? = null
var weather: WeatherDataJson? = null
}
here is my interface class
interface ApiInterface {
#GET("data/2.5/weather?q=Prague")
fun getWeatherData(#Query("appid") appId: String)
: Call<WeatherData>
}
My TemperatureData class
data class TemperatureData(var temp: String)
And my WeatherDataJson class
data class WeatherDataJson(var description:String)
In my mainclass i have a function to show the json into my screen but i can't load the "var weather..."
Here is the function
private fun getTemperatureData(repository: Repository) {
repository.getApiInterface()
.getWeatherData("4cf7f6610d941a1ca7583f50e7e41ba3")
.enqueue(object : Callback<WeatherData> {
override fun onFailure(call: Call<WeatherData>?, t: Throwable?) {
t?.printStackTrace()
}
override fun onResponse(call: Call<WeatherData>?, response: Response<WeatherData>?) {
val weatherData: WeatherData? = response?.body()
weatherData?.let {
it.main?.let {
tempText.text = it.temp
}
it.weather?.let{
weatherTextFromApi.text=it.description
}
}
}
})
}
On the description is says unresolved reference description
If you use openweathermap api declare those data classes
data class WeatherData(
#SerializedName("coord") val coord: Coord,
#SerializedName("weather") val weather: List<Weather>,
#SerializedName("base") val base: String,
#SerializedName("main") val main: TemperatureData,
#SerializedName("visibility") val visibility: Int,
#SerializedName("wind") val wind: Wind,
#SerializedName("clouds") val clouds: Clouds,
#SerializedName("dt") val dt: Int,
#SerializedName("sys") val sys: Sys,
#SerializedName("id") val id: Int,
#SerializedName("name") val name: String,
#SerializedName("cod") val cod: Int
)
data class Sys(
#SerializedName("type") val type: Int,
#SerializedName("id") val id: Int,
#SerializedName("message") val message: Double,
#SerializedName("country") val country: String,
#SerializedName("sunrise") val sunrise: Int,
#SerializedName("sunset") val sunset: Int
)
data class Coord(
#SerializedName("lon") val lon: Double,
#SerializedName("lat") val lat: Double
)
data class TemperatureData(
#SerializedName("temp") val temp: Double,
#SerializedName("pressure") val pressure: Int,
#SerializedName("humidity") val humidity: Int,
#SerializedName("temp_min") val tempMin: Double,
#SerializedName("temp_max") val tempMax: Double
)
data class Weather(
#SerializedName("id") val id: Int,
#SerializedName("main") val main: String,
#SerializedName("description") val description: String,
#SerializedName("icon") val icon: String
)
data class Clouds(
#SerializedName("all") val all: Int
)
data class Wind(
#SerializedName("speed") val speed: Double,
#SerializedName("deg") val deg: Int
)
if you goal is get description from weather all you need will be
weatherData.weather.firstOrNull()?. description ?: ""
For getting url of icon
It is kind of tricky, you could get url from response but only url of icon.
val iconId = weatherData.weather.firstOrNull()?. description
val iconUrl = iconId?.let{"http://openweathermap.org/img/w/${it}.png"} ?: ""
After that you should use Glide library or Picasso for loading imageUrl to ImageView
See more about Glide here https://github.com/bumptech/glide
The server response from OpenWeatherMap is returning a JSON array, not a JSON object, for weather. Gson/Retrofit cannot automatically turn an array into a single Object, so you need to change your data class to hold a List (or use a custom Gson deserializer and manually grab the item you want from the array).
Example of what your top level class should be:
class WeatherData {
var main: TemperatureData? = null
var weather: List<WeatherDataJson>? = null
}

Categories

Resources