Max Siomin
Max Siomin

Reputation: 95

Why do I have error while building project?

I watched the youtube video and implemented database in my project
Database.kt:

@Database(entities = [Result::class], version = DATABASE_VERSION, exportSchema = false)
abstract class ResultDatabase : RoomDatabase() {

abstract fun resultDao(): ResultDao

companion object {
    @Volatile
    private var INSTANCE: ResultDatabase? = null

    fun getDatabase(context: Context): ResultDatabase {
        val tempInstance = INSTANCE

        if (tempInstance != null) {
            return tempInstance
        }

        synchronized(this) {
            val instance = Room.databaseBuilder(
                context.applicationContext,
                ResultDatabase::class.java,
                TABLE_NAME
            ).build()

            INSTANCE = instance

            return instance
        }
    }
}

}

ResultClass.kt:

@Entity(tableName = TABLE_NAME)
data class Result(private val id: Int,
              private val cheatingEnabled: Boolean,
              private val cheatingSuccessful: Boolean,
              private val min: Long,
              private val max: Long,
              private val result: Long,
              private val time: LocalDateTime

)

ResultDao.kt:

@Dao
interface ResultDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun addResult(result: Result)

    @Query(value = "SELECT * FROM random_data ORDER BY id ASC")
    fun getAllResults(): LiveData<List<Result>>
}

Repo.kt

class ResultsRepository(private val resultDao: ResultDao) {
    val resultHistory: LiveData<List<Result>> = resultDao.getAllResults()

    fun addResult(result: Result) {
        resultDao.addResult(result)
    }
}

Function that inserts data to database:

private fun insertDataToDatabase(min: Long,
                                 max: Long,
                                 result: Long,
                                 cheatingEnabled: Boolean,
                                 cheatingSuccessful: Boolean
) {
    val time = LocalDateTime.now()
    val resultEntity = Result(0, cheatingEnabled, cheatingSuccessful, min, max, result, time)
    viewModelScope.launch {
        repository.addResult(resultEntity)
    }
}

Error:

C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:14: error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final java.time.LocalDateTime time = null;
                                      ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:8: error: Cannot find getter for field.
private final int id = 0;
                  ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:9: error: Cannot find getter for field.
private final boolean cheatingEnabled = false;
                      ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:10: error: Cannot find getter for field.
private final boolean cheatingSuccessful = false;
                      ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:11: error: Cannot find getter for field.
private final long min = 0L;
                   ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:12: error: Cannot find getter for field.
private final long max = 0L;
                   ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:13: error: Cannot find getter for field.
private final long result = 0L;
                   ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:14: error: Cannot find getter for field.
private final java.time.LocalDateTime time = null;
                                      ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:7: error: An entity must have at least 1 field annotated with @PrimaryKey

public final class Result { ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:14: error: Cannot figure out how to read this field from a cursor. private final java.time.LocalDateTime time = null; ^

How can I fix this error? Can it be connected with using LocalDateTime datatype and Long instead of int? But I don't even start inserting, I get errors while building. I saw similar questions and there people adviced to use json objects, but man from youtube has project without json and withoutany errors.

Upvotes: 1

Views: 369

Answers (1)

CommonsWare
CommonsWare

Reputation: 1007554

Can it be connected with using LocalDateTime datatype and Long instead of int?

Yes.

But I don't even start inserting, I get errors while building

Room uses an annotation processor — that is the kapt statement you added to your dependencies. That annotation processor does not know what to do with a LocalDateTime. And, it cannot work with private Kotlin properties.

How can I fix this error?

Start by removing the private keyword from those properties on Result. That should reduce the errors to 2, both for LocalDateTime.

Then, you will need to teach Room how to work with LocalDateTime.

For that, you will need a class with a pair of @TypeConverter functions that can convert between LocalDateTime and... something. In this sample, I have type converters between Instant and Long:

import androidx.room.TypeConverter
import java.time.Instant

class TypeTransmogrifier {
  @TypeConverter
  fun fromInstant(date: Instant?): Long? = date?.toEpochMilli()

  @TypeConverter
  fun toInstant(millisSinceEpoch: Long?): Instant? = millisSinceEpoch?.let {
    Instant.ofEpochMilli(it)
  }
}

Then, you will need to add a @TypeConverters annotation (note the trailing s) to something to register your class with the @TypeConverter annotations. One simple place to do this is on your @RoomDatabase class, as I do in this sample:

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters

private const val DB_NAME = "stuff.db"

@Database(entities = [ToDoEntity::class], version = 1)
@TypeConverters(TypeTransmogrifier::class)
abstract class ToDoDatabase : RoomDatabase() {
  abstract fun todoStore(): ToDoEntity.Store

  companion object {
    fun newInstance(context: Context) =
      Room.databaseBuilder(context, ToDoDatabase::class.java, DB_NAME).build()
  }
}

Given those two things, in my sample project, any of my entities can use Instant. You would do the same thing, just for LocalDateTime (or, perhaps, switch your entities from using LocalDateTime to using Instant).

You can read more about this in the documentation.

Upvotes: 1

Related Questions