[Room] error: Cannot figure out how to save this field into database 문제 해결

 

에러 내용 

error: Cannot figure out how to save this field into database. 
You can consider adding a type converter for it. 
error: Cannot figure out how to read this field from a cursor.

 

Room Database를 사용하던 중에 위와 같은 에러가 발생했습니다.

Room에 데이터를 저장할 때는 primitive type과 wrapping type만 지원합니다.

따라서 그 외의 LIst나 커스텀 클래스를 저장할 경우에는 converter를 지정해주여야 한다고 합니다. Converter의 사용법을 익혀서 문제를 해결해는 방식을 학습했습니다.

 

 

Entity

@Entity(tableName = "mainFeeds")
data class MainFeedEntity (
    @PrimaryKey val recordId :Int,
    val title : String,
    val description : String,
    val placeTitle : String,
    val placeLatitude : Int,
    val placeLongitude : Int,
    val thumbnailUrl : String,
    val interestType : String,
    val user : UserInfo,
    val files : List<FeedFile>,
    val readCount : Int, // user가 몇번 접근했는지 확인
    val isNumbering : Boolean, // user가 지수 평가를 했는지 확인
    val recordScore : Int
)

 

저의 코드에서는 위와 같은 엔티티를 사용합니다.

메인 피드에서 보여줄 데이터를 룸에 저장하기 위해서 생성한 엔티티이며, 

primitive type이 아닌 리스트와 커스텀 클래스인 UserInfo에 대한 Converter를 지정 해주어야 합니다.

 

gson 라이브러리

    // gson
    implementation("com.google.code.gson:gson:2.9.0")

https://github.com/google/gson

 

GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back

A Java serialization/deserialization library to convert Java Objects into JSON and back - GitHub - google/gson: A Java serialization/deserialization library to convert Java Objects into JSON and back

github.com

Room 데이터 베이스에 JSON 값들을 저장하기 위해서는 파싱해주는 역할을 하는 라이브러리가 필요합니다.

Gson은 자바 객체를 Json 표현으로 변환하는 데 사용할 수 있는 자바 라이브러리 입니다.

JSON 문자열을 동등한 자바 객체로 변환하는 데에도 사용할 수 있으며, 

Key - Value 형태로 구성되어진 데이터 타입을 반환합니다.

 

Room 데이터베이스의 Converter를 지정하기 위해서 위 라이브러리를 사용합니다.

TypeConverter

@ProvidedTypeConverter
class FileListConverters {
    @TypeConverter
    fun listToJson(value: List<FeedFile>) : String? {
        return Gson().toJson(value)
    }

    @TypeConverter
    fun jsonToList(value : String) : List<FeedFile> {
        return Gson().fromJson(value,Array<FeedFile>::class.java).toList()
    }
}

 

우선 리스트에 대한 TypeConverter를 선언했습니다.

저의 경우에는 List와 커스텀 뷰가 결합 된 List<FeedFile>을 사용하였는데,

커스텀 뷰가 리스트로 묶여있는 경우에는 하나의 따로 FeedFile Converter를

생성할 필요는 없고 하나의 TypeConverter로 변환이 가능합니다.

 

 

@ProvidedTypeConverter
class UserStringConverters {
    @TypeConverter
    fun userToJson(value : UserInfo) : String? {
        return Gson().toJson(value)
    }

    @TypeConverter
    fun jsonToUser(value : String) : UserInfo{
        return Gson().fromJson(value,UserInfo::class.java)
    }
}

 

위는 커스텀 뷰인 UserInfo에 대한 변환 정책을 지정해주었습니다.

총 2개의 converter를 생성하였는데, 각 2개의 함수를 가지고 있습니다.

리스트를 String으로 변환하고, String을 다시 리스트로 변환하는 기능을 가지고 있으며,

다른 하나의 converter에서는 커스텀 뷰를 String으로 변환과 역변환을 하는 기능을 가지고 있습니다.

 

위의 예제처럼 TypeConverter를 정의한 뒤, RoomDatabase 객체에 등록해주면 됩니다.

 

RoomDatabase

@Database(entities = [MainFeedEntity::class, RemoteKeysEntity::class]
    , version = 1)
@TypeConverters(
    value = [
        FileListConverters::class,
        UserStringConverters::class
    ]
)
abstract class MainFeedDatabase : RoomDatabase() {

    abstract fun getMainFeedDao() : MainFeedDao

    abstract fun remoteKeyDao() : RemoteKeysDao
}

 

TypeConverters 어노테이션을 지정하고, 위에서 설정한 Converter 클래스를 지정해주면 됩니다.

에러를 해결해서 성공적으로 빌드할 수 있었습니다.