Given the Entity:
@Entity(tableName = "otp_tokens")
data class DBEntity (
@PrimaryKey(autoGenerate = true)
val id: Long,
val data: String,
val encryptionType: EncryptionType
)
EncryptionType
:
enum class EncryptionType {
PLAIN_TEXT,
ENCRYPTED
}
I want to use a @TypeConverter
to encrypt/decrypt the data
String field when accessing the database, based on the value of the encryptionType
field value. So for example if encryptionType == PLAIN_TEXT
the TypeConverter should not do anything with the String value, but if encryptionType == ENCRPYTED
it should encrypt/decrypt the data
field.
When I write a TypeConverter
for the data
field I only get the String value of data
in the encrypt/decrypt methods of the Converter and have no access to the encryptionType
field, so how can I implement this?
Type Converters will only convert an unhandled Type to a Type that can be handled (stored).
So your options would be to
data
member/field as such a (unhandled) Type, orHere's an example of the latter.
First the data field is changed to var to allow it's manipulation (encryption/decryption). Then the encryption/decryption functions are added so DBEntity becomes:-
@Entity(tableName = "otp_tokens")
data class DBEntity (
@PrimaryKey(autoGenerate = true)
val id: Long,
var data: String,
val encryptionType: EncryptionType
) {
fun encryptData() {
if (this.encryptionType.equals(EncryptionType.ENCRYPTED) ) {
val sb = StringBuilder()
for (i in 0..this.data.length - 1) {
sb.append("~", this.data[i])
}
this.data = sb.toString()
}
}
/* Not Tested/Used in the demo */
fun decryptData(): String {
if (this.encryptionType.equals(EncryptionType.ENCRYPTED)) {
val sb = StringBuilder()
for (i in 0..this.data.length - 2 step 2) {
sb.append(this.data[i + 1])
}
return this.data
} else {
return this.data
}
}
}
obviously the encryption is just a very simple change to the data and that whatever encryption/decryption process you would want to implement would replace the method used for the example/demo.
As stated a DAO function could then utilise the above to encrypt or not encrypt when inserting, so the @Dao annotated interface could include:-
@Dao
interface DBEntityDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(dbEntity: DBEntity)
fun insertAndEncrypt(dbEntity: DBEntity) {
dbEntity.encryptData()
insert(dbEntity)
}
}
Putting this into action (note .allowMainThreadQueries
has been utilised for brevity and convenience), the following is coded in an activity:-
db = TheDatabase.getInstance(this)
dao = db.getDBEntityDao()
val d1 = DBEntity(0,"Rumplestiltskin",EncryptionType.PLAIN_TEXT)
val d2 = DBEntity(0,"Rumplestiltskin",EncryptionType.ENCRYPTED)
dao.insert(d1)
dao.insert(d2)
dao.insertAndEncrypt(d1)
dao.insertAndEncrypt(d2)
The resultant data, view via App Inspection:-
As can be seen:-