Storing a nested JSON object into Android Persistence Library - android

from my local Django Rest Framework service I get the following JSON output:
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"created": "2020-04-18T16:00:16.060915Z",
"name": "Germany",
"groups": [
{
"id": 1,
"created": "2020-04-18T16:03:11.138661Z",
"name": "MyGroup1",
"owner_id": 1
},
{
"id": 2,
"created": "2020-04-18T16:03:20.701660Z",
"name": "MyGroup2",
"owner_id": 1
},
...
Each Country can have many Groups. For this I have created the following data classes in my Android App project:
#JsonClass(generateAdapter = true)
data class NetworkCountryContainer(
val count: Long,
val next: String?,
val previous: String?,
val results: List<Country>
)
#Entity(tableName = "country_table")
#JsonClass(generateAdapter = true)
data class Country(
#PrimaryKey
#Json(name="id")
val countryId : Int,
#Json(name="name")
val countryName: String,
#Json(name="groups")
val groupList: List<Group> // <--- this field causes the ERROR
)
#Entity(tableName = "group_table")
#JsonClass(generateAdapter = true)
data class Group(
#PrimaryKey
#Json(name="id")
val groupId : Int,
#Json(name="name")
val groupName: String,
#Json(name="owner_id")
val ownerId: Int
)
Android Studio tells me this:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
Why I need a TypeConverter ? And how can I build one ?

Related

Retrofit parse JSON into different models

I want to parse JSON like below:
{
"result": 0,
"list": [
{
"id": 58,
"type": "58",
"name": "fooGroup",
"foos": {
"id": "1",
"name": "33",
}
]
}
If I define models like this:
data class Response(val result: Int,
#SerializedName("list") val fooGroup: List<FooGroupResponse>)
data class FooGroupResponse(val id: Int, val type: String, val name: String,
#SerializedName("foos") val fooGroup: List<Foo>?)
data class Foo(val id: Int, val name: String)
then everything works fine.
Right now I want to take these out as a model:
"id": 58,
"type": "58",
"name": "fooGroup",
That is add one more model FooGroup like below:
data class Response(val result: Int,
#SerializedName("list") val fooGroup: List<FooGroupResponse>)
data class FooGroupResponse(val fooGroup: FoolGroup,
#SerializedName("foos") val fooGroup: List<Foo>?)
data class Foo(val id: Int, val name: String)
data class FooGroup(val id: Int, val type: String, val name: String)
But there's no #SerializedName can be set for FooGroup, is it possible?
Thanks.
I think you will have to restructure your JSON. The parser is going to make a faithful representation of the JSON string as a Java object. Your first example is the faithful representation. What you want to do is not faithful to the JSON received.
{
"result": 0,
"list": [
{
"fooGroup": {
"id": 58,
"type": "58",
"name": "fooGroup"
},
"foos": [
{
"id": "1",
"name": "33"
}
]
}
]
}
BUT you can do it manually where you parse the object yourself. Here is a how to with GSON but it should be easily convertible if you prefer another lib.
https://www.woolha.com/tutorials/retrofit-2-define-custom-gson-converter-factory
Simply pull "id", "type", "name" from the JSON as its deserializing and make a composite data class.
data class FooGroup(val id: Int, val type: String, val name: String)
//You deserialize you JSON into a List of Foos
data class Foos(val foo: Foo, val fooGroup : FooGroup)

Kotlin | Jackson annotation | How to fix Out of START_ARRAY token Error

Can anybody say where I am doing wrong. I have json like that
[
{
"id": "1",
"name": "ff",
"surname": "ggg",
"cap": "10000"
},
{
"id": "1",
"name": "aaa",
"surname": "hhh",
"cap": "22222"
},
{
"id": "1",
"name": "rrr",
"surname": "hhhhhdr",
"cap": "33333"
},
{
"id": "1",
"name": "hhh",
"surname": "qqqqq",
"cap": "44444"
}
]
And I parse to this class.
data class ResponseList(
val capList: List<Response>?
) {
data class Response(
#JsonProperty("id")
val id: String,
#JsonProperty("name")
val name: String,
#JsonProperty("surname")
val surname: String,
#JsonProperty("cap")
val cap: String
)
}
When I try to parse it the list is always null and if I try to test it I have this error:
Cannot deserialize value of type com.myapp.ResponseList from Array value (token JsonToken.START_ARRAY)
just class Response is needed, like following:
fun test(){
val jsonStr = "your json str"
val mapper = ObjectMapper()
val lendReco: List<Response> =
mapper.readValue(jsonStr, object : TypeReference<List<Response?>?>() {})
}
data class Response(
#JsonProperty("id")
val id: String,
#JsonProperty("name")
val name: String,
#JsonProperty("surname")
val surname: String,
#JsonProperty("cap")
val cap: String
)

How to select specific part of JSON and convert it to a List in retrofit with Moshi

I'm getting the JSON blow from an API with retrofit and I want to only select the production_companies array from it and convert it to a list of ProductionCompanie class, how I can do it with Moshi without using nested classes?
{
"backdrop_path": "/52AfXWuXCHn3UjD17rBruA9f5qb.jpg",
"belongs_to_collection": null,
"budget": 63000000,
"genres": [
{
"id": 18,
"name": "Drama"
}
],
"homepage": "http://www.foxmovies.com/movies/fight-club",
"id": 550,
"popularity": 40.054,
"poster_path": "/8kNruSfhk5IoE4eZOc4UpvDn6tq.jpg",
"production_companies": [
{
"id": 508,
"logo_path": "/7PzJdsLGlR7oW4J0J5Xcd0pHGRg.png",
"name": "Regency Enterprises",
"origin_country": "US"
},
{
"id": 711,
"logo_path": "/tEiIH5QesdheJmDAqQwvtN60727.png",
"name": "Fox 2000 Pictures",
"origin_country": "US"
},
{
"id": 20555,
"logo_path": "/hD8yEGUBlHOcfHYbujp71vD8gZp.png",
"name": "Taurus Film",
"origin_country": "DE"
},
{
"id": 54051,
"logo_path": null,
"name": "Atman Entertainment",
"origin_country": ""
}
],
"vote_count": 21181
}
this is my retrofit Apis interface:
interface Apis {
#Headers("Content-Type: application/json")
#GET("/3/movie/550")
fun getData(#Query("api_key") key: String = apiKey): Call<List<ProductionCompanie>>
}
and my model:
#JsonClass(generateAdapter = true)
data class ProductionCompanie(
#Json(name = "id")
val id: Int,
#Json(name = "logo_path")
val picture: String,
#Json(name = "name")
val name: String
)
I ended up using a custom adapter:
class ProductionCompanieListAdapter(private val moshi: Moshi) {
#FromJson
fun fromJson(value: JsonReader): List<ProductionCompanie>? {
val json = JSONObject(value.nextSource().readUtf8())
val jsonArray = json.getJSONArray("production_companies")
val type = Types.newParameterizedType(List::class.java, ProductionCompanie::class.java)
val adapter = moshi.adapter<List<ProductionCompanie>>(type)
return adapter.fromJson(jsonArray.toString())
}
#ToJson
fun toJson(value: List<ProductionCompanie>): String {
val type = Types.newParameterizedType(List::class.java, ProductionCompanie::class.java)
val adapter = moshi.adapter<List<ProductionCompanie>>(type)
return adapter.toJson(value)
}
}

how to use #Relation in Room

{
"id": 7,
"title": "Reading monthly hot list in January",
"img_url": "http://image.wufazhuce.com/FteWZbumJ0vugA_oF-tjk9OxOhT5",
"contents": [
{
"id": "4582",
"title": "How to say goodbye",
"subtitle": "Gengsheng Su",
"category": 1,
"cover": "http://image.wufazhuce.com/FnBm-nZ-fQIit227taKI9Tue_9sx?imageView2/1/w/120/h/120",
"maketime": "2021-01-20 06:00:00",
"weight": 15
},
{
"id": "4567",
"title": "Go to RT Mart",
"subtitle": "Zhanhei Wang",
"category": 1,
"cover": "http://image.wufazhuce.com/Fv2ZTzdL0LjfzB8q5N_mp_7h5Ti8?imageView2/1/w/120/h/120",
"maketime": "2021-01-09 06:00:00",
"weight": 14
},
{
"id": "4560",
"title": "cLOUD MADE BY RAIN",
"subtitle": "GongChen",
"category": 1,
"cover": "http://image.wufazhuce.com/FnZhpbcENaSm6Fmnjfxaz0oAgXzo?imageView2/1/w/120/h/120",
"maketime": "2021-01-01 06:00:00",
"weight": 13
}
]
}
I want to use this json convert to bean,and store it in my Room.
But I don't know how to store it.Maybe I'm not familiar with Room.
I tried to use it by
#Entity(tableName = "rebang_cache")
data class ReBang(
#PrimaryKey
var id: Int,
var title: String?,
var img_url: String?,
#Relation(
parentColumn = "id",
entityColumn = "id")
val contents: List<ContentBean>?) {
#Entity
data class ContentBean(#PrimaryKey
var id: String,
var title: String?,
var subtitle: String?,
var category: Int?,
var cover: String?,
var maketime: String?,
var weight: Int?)
}
But it is error.I want to know how to implement it.
I think this is a good question!
You need to define entity classes for both parent and child first:
#Entity(tableName = "rebang_cache")
data class ReBang(
#PrimaryKey
val id: Long,
val title: String
//...)
#Entity
data class ContentBean(
#PrimaryKey val id: Long,
//parent model reference id
val rebangId: Long,
val title: String,
//..)
Then define one-to-many relationship using #Relation annotation
data class ReBangWithContents(
#Embedded val rehang: ReBang,
#Relation(
parentColumn = "id"
entityColumn = "rebangId"
)
val contents: List<ContentBean>
)

How to generate request model having same object which having multiple types

How to generate request model having same object which having multiple types:
{
"questionnaire": 2,
"response": [
{
"answer": {
"id": 8,
"option_data": {
"description": "",
"text": "As much as i ever did",
"value": "4"
}
},
"question_id": 4
},
{
"answer": {
"option_data1": [
{
"text": "",
"value": 2
}
]
},
"question_id": 2
}
]
}
There is a plugin AS Json to DataClass convertor. You can find here
data class s(
val questionnaire: Int?, // 2
val response: List<Response>? )
data class Response(
val answer: Answer?,
#Json(name = "question_id")
val questionId: Int? // 4 )
data class OptionData1(
val text: String?,
val value: Int? // 2 )
data class OptionData(
val description: String?,
val text: String?, // As much as i ever did
val value: String? // 4 )
data class Answer(
val id: Int?, // 8
#Json(name = "option_data")
val optionData: OptionData?,
#Json(name = "option_data1")
val optionData1: List<OptionData1>? )
As you see there is ? in some fields. You can use it

Categories

Resources