3

Not sure what is causing this, but i am trying request data from the api which includes an array of Message objects. If i print the result to the console, the data is correct apart from Messages=null when i would expect Message to be an array of objects. I can't understand what i've missed?

I'm getting this error: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter messages

Could anyone point me in the right direction? Code below for the class:

const val PROFILE_RESPONSE_ID = 0

@Entity(tableName = "profile")
data class ProfileResponse(
    val id: Int,
    val name: String,
    val code: String,
    val title: String,
    @SerializedName("profile_image")
    val profileImage: String,
    @SerializedName("background_image")
    val backgroundImage: String,
    @Embedded(prefix = "messages_")
    val messages: ArrayList<Messages>,
) {
    @PrimaryKey(autoGenerate = false)
    var responseId: Int = PROFILE_RESPONSE_ID
}

Sample JSON:

{
  "id": 44,
  "name": "Jason",
  "code": "jason",
  "title": "Jason Scott",
  "profile_image": "https://sampleurl.com/sample_profile.jpg",
  "background_image": "",
  "messages": [
    {
      "id": 0001,
      "message": "Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.",
      "timestamp": "Thu, 01 Jan 1970 01:00:00 +0100",
    }
    {
      "id": 0002,
      "message": "Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.",
      "timestamp": "Thu, 01 Jan 1970 01:00:00 +0100",
    }
    {
      "id": 0003,
      "message": "Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.",
      "timestamp": "Thu, 01 Jan 1970 01:00:00 +0100",
    }
}
Jason
  • 209
  • 2
  • 13
  • 1
    Like you mentioned `messages` is null but the kotlin compiler thinks `messages` not null and you're trying to set it null. – Srikar Reddy Jan 08 '19 at 17:28
  • But it shouldn't be null nor am i trying to set it to be null (not intentionally anyway), it should have the array of `message` objects pulled down from the api? – Jason Jan 08 '19 at 17:29
  • Check if the server is sending you the `messages_` json object and it is properly getting converted to array list of `messages`. – Srikar Reddy Jan 08 '19 at 17:34
  • Not sure if this makes much difference but originally was `List` but was getting `e: error: Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). - java.util.List` so converted it to a `List`. Does it need to be a `List` or should `ArrayList` work just fine? (or an array of objects) – Jason Jan 08 '19 at 17:39
  • That error was that Room was unable to figure the right constructor. `List` or `ArrayList` doesn't matter. Update the question with sample json that you may recevie from the server. – Srikar Reddy Jan 08 '19 at 17:57
  • And, you're trying to save it to multiple tables right? – Srikar Reddy Jan 08 '19 at 17:57
  • Please test your api with Postman then check all the data in response – Ashish Jan 08 '19 at 18:04
  • Added some sample JSON to the question. Sorry, still learning but I thought `@Embedded` means it embeds within the `profile` table? So it would result in `messages_id`, `messages_message` etc. It doesn't need to be in its own table but if I remove `@Embedded` i get an error: `error: Cannot figure out how to save this field into database. You can consider adding a type converter for it. private final java.util.List messages = null;` – Jason Jan 09 '19 at 10:18
  • 1
    @Jason Embedded works for a single object to embed its fields in the entity table. In the case of a List of objects, you have a one to many relation and this is modeled in Room with a Relation annotation in a new pojo(along with some changes to your current code). https://developer.android.com/training/data-storage/room/defining-data#object-relationships – user Jan 09 '19 at 10:48

1 Answers1

3

Managed to solve this by removing @Embedded as I didn't necessarily need the data in another table, and added a TypeConverter to convert the list into a String and back (This question helped). For reference for anyone else:

TypeConvertor Class

class Convertors {

    @TypeConverter
    fun listToJson(value: List<Message>?): String {
        return Gson().toJson(value)
    }

    @TypeConverter
    fun jsonToList(value: String): List<Message>? {
        val objects = Gson().fromJson(value, Array<Message>::class.java) as Array<Message>
        val list = objects.toList()
        return list
    }

}

Then adding the @TypeConverters to my database class.

Database Class

@Database(entities = [ProfileResponse::class], version = 1)
@TypeConverters(Convertors::class)
abstract class MainDatabase: RoomDatabase() {

    abstract fun profileResponseDao(): ProfileResponseDao

}
Jason
  • 209
  • 2
  • 13