I'm editing an existing entity of my project which looks like this (i added the sessionSettings field):
data class Patient(
// ... other fields
@Expose
@SerializedName("exo_settings")
@Embedded
var exoSettingsData: ExoSettingsData? = null, // already exist
@Expose
@SerializedName("session_settings")
@TypeConverters(SessionSettingsConverters::class)
var sessionSettings: SessionSettings? = null, // the new field
/// ... other fields
)
My TypeConverter class:
class SessionSettingsConverters {
private var gson = Gson()
@TypeConverter
fun stringToSessionSettings(data: String?): SessionSettings? {
if (data.isNullOrEmpty()) {
return null
}
val sessionSettingsType = object : TypeToken<SessionSettings>() {}.type
return gson.fromJson(data, sessionSettingsType)
}
@TypeConverter
fun sessionSettingsToString(someObject: SessionSettings): String? {
return gson.toJson(someObject)
}
}
I added the sessionSettings; which is a basic object containing strings and integers, and it's TypeConverter to ease the integration. My issue is, i need this field to be null by default, because if it is, i'm grabbing data from another source. The problem is if I do so, my unit tests get broken if I do for exemple this:
val patient1 = Patient("1", synkStatus = SynkStatus.DELETED)
centerDatabase.patientDao().savePatient(patient1).test()
It fails (the entity is not saved), but if I initialize a SessionSettings object it works:
val patient1 = Patient("1", synkStatus = SynkStatus.DELETED, sessionSettings = SessionSettings())
centerDatabase.patientDao().savePatient(patient1).test()
So my question is: is there a way to allow saving this entity without initializing this field to keep it null by default ? Or the only way would be to add a boolean to track if this field as been edited or not ?
Thanks
The Issue Your issue appears to be that the TypeConverter will not accept a null when converting a SessionsSettings.
The Fix
Change to use someObject: SessionSettings?
i.e. added the ?
Working Example/Demonstration
The following demonstrates the subtle change using code that is based upon your code i.e.:-
data class SessionSettings(
val ssname: String,
val ssine: Int
)
@Entity
data class Patient(
@PrimaryKey
val patientId: Long?=null,
val patientName: String?=null,
var sessionSettings: SessionSettings?, // the new field
/// ... other fields
)
class SessionSettingsConverters {
private var gson = Gson()
@TypeConverter
fun stringToSessionSettings(data: String?): SessionSettings? {
if (data.isNullOrEmpty()) {
return null
}
val sessionSettingsType = object : TypeToken<SessionSettings>() {}.type
return gson.fromJson(data, sessionSettingsType)
}
@TypeConverter
fun sessionSettingsToString(someObject: SessionSettings?): String? {
return gson.toJson(someObject)
}
}
@Dao
interface SO75530351DAO {
@Insert
fun insert(patient: Patient): Long
@Query("SELECT * FROM patient")
fun getAllPatients(): List<Patient>
}
@TypeConverters(SessionSettingsConverters::class)
@Database(entities = [Patient::class], exportSchema = false, version = 1)
abstract class SO75530351DB: RoomDatabase() {
abstract fun getDao(): SO75530351DAO
companion object {
private var instance: SO75530351DB?=null
fun getInstance(context: Context): SO75530351DB {
if (instance==null) {
instance=Room.databaseBuilder(context,SO75530351DB::class.java,"so75539351.db")
.allowMainThreadQueries()
.build()
}
return instance as SO75530351DB
}
}
}
And to use the above:-
dbx = SO75530351DB.getInstance(this)
daox = dbx.getDao()
daox.insert(Patient(patientName = "Fred"))
daox.insert(Patient(patientName = "Mary", sessionSettings = SessionSettings("SESSION1",10)))
for(p in daox.getAllPatients()) {
Log.d("DBINFO","Patient is ${p.patientName} ID is ${p.patientId} ${p.sessionSettings}")
}
The Log, after running:-
D/DBINFO: Patient is Fred ID is 1 null
D/DBINFO: Patient is Mary ID is 2 SessionSettings(ssname=SESSION1, ssine=10)
The database, via App Inspection, :-