Reputation: 1538
I'm using retrofit and kotlin for my andorid app.
For one of my APIs, I have the following data classes
class Set(val set_id: Long, val tickets: List<Ticket>, val timer: Int) {}
class Ticket(val ticket_id: Long, val rows: List<Row>) {}
class Row(val row_id: Long, val row_numbers: List<Int>) {}
Sample JSON DATA
{
"set_id": 60942,
"tickets": [
{
"ticket_id": 304706,
"rows": [
{
"row_id": 914116,
"row_numbers": [
0,
11,
21,
0,
42,
52,
0,
76,
85
]
}
]
}
],
"timer": 12
}
Set
class contains a list of Ticket
and each ticket has a list of Row
My JSON object contains only these values and it is working fine till here. Retrofit mapping is also working.
Problem:
I want to add my own a boolean field/variable isPlaying
for class Ticket
, which will be updated in the app later. But, this field should be set to true by default.
So I've tried this
class Ticket(val ticket_id: Long, val rows: List<Row>, var isPlaying: Boolean = true) {}
and this
class Ticket(val ticket_id: Long, val rows: List<Row>) {
var isPlaying: Boolean = true
}
NOTE: JSON doesn't have isPlaying
key, I want it for app logic only.
Both did not work, isPlaying
is always showing false
. I want it to be true
by default.
Please, help me out. Thank you!
Upvotes: 9
Views: 4924
Reputation: 336
Default arguments would not work in data class in the case when objects are instantiated with retrofit due to parsing library used underneath, which probably creates objects without calling constructor. For example Gson
uses sun.misc.Unsafe
to create objects.
What you can do - is to add backing property for fields that have default values:
class Ticket(
val ticket_id: Long,
val rows: List<Row>,
private var _isPlaying: Boolean? = true
) {
var isPlaying
get() = _isPlaying ?: true
set(value) {
_isPlaying = value
}
}
Upvotes: 4
Reputation: 10126
The root of the problem is the fact that GSON creates object not via constructor call, but via Unsafe staff. Thus it leads to broken things like null-safety or property initialization.
The only way I know how to workaround your case looks like this:
class Ticket(val ticket_id: Long, val rows: List<Row>) {
private var _isPlaying: Boolean? = null
var isPlaying: Boolean
get() = _isPlaying ?: true // <-- default value
set(value) {
_isPlaying = value
}
}
Here we create one backing property _isPlaying
which will be initialized to null by GSON. Next we add custom getter and setter for public property which checks each it is invoked if _isPlaying
is null. And if so it returns your default value. Otherwise, it returns the value stored in _isPlaying
Yes, it looks ugly. Otherwise you should consider using another json library like Jackson which as I know supports Kotlin well.
Upvotes: 1
Reputation: 1802
With using GsonBuilder setFeildNamePolicy
val gson = GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create()
val info = gson.fromJson(json, Account::class.java)
data class Account(
@SerializedName("user_name") var userName: String = "",
@SerializedName("ticket_id") var ticketId: String = "",
@SerializedName("row_id") var rowId: String = "")
}
Upvotes: -1