Проблема с @Ignore и неизменяемыми полями

#android #kotlin #android-room

#Android #kotlin #android-комната

Вопрос:

У меня проблема с местом.

Я использую обновление с помощью Gson converter для rest api, и я хотел бы поделиться pojos с room. В целом это работает, но в некоторых случаях мне нужно игнорировать некоторые поля, потому что у меня есть список объектов. Я пытался использовать аннотацию @Ignore, но при ее использовании процесс сборки завершается неудачей со следующими ошибками:

ошибка: Сущности и Pojos должны иметь доступный для использования общедоступный конструктор. У вас может быть пустой конструктор или конструктор, параметры которого соответствуют полям (по имени и типу). общедоступный сервис конечного класса {

^ ошибка: не удается найти параметр для поля. закрытый конечный java.lang.Идентификатор строки = null;

^ ошибка: не удается найти параметр для поля. закрытый конечный java.lang.Имя строки = null;

^ ошибка: не удается найти параметр для поля. закрытый конечный java.lang.Описание строки = null;

Итак, используя этот класс, все работает:

 @Entity(tableName = "services")
data class Service(

    @PrimaryKey val id: String,
    val name: String,
    val description: String,
    val parentId: String?
)
  

При этом происходит сбой:

 @Entity(tableName = "services")
data class Service(

    @PrimaryKey val id: String,
    val name: String,
    val description: String,
    val parentId: String?,
    @Ignore val test: String
)
  

Я использую эту версию room:

 implementation 'androidx.room:room-runtime:2.1.0-alpha06'
kapt 'androidx.room:room-compiler:2.1.0-alpha06'
  

Я знаю, что проблему можно было бы устранить, используя var вместо val и добавив дополнительный конструктор, но я не хочу этого делать, я предпочитаю сохранять неизменяемое состояние моих полей.

Это ошибка аннотации ignore? Почему без этого все работает? Любая помощь приветствуется 🙂

Ответ №1:

Во втором примере сервис будет переведен в класс Java, который имеет один конструктор с четырьмя параметрами. Room видит аннотации @Ignore и знает, что ему нужно связать 3 поля, и поэтому ему нужен конструктор с 3 параметрами, соответствующими этим типам полей. Поскольку он не находит такой конструктор (или конструктор по умолчанию), он завершается с ошибкой.

Попробуйте сделать последнее свойство необязательным и использовать аннотацию @JvmOverloads в конструкторе:

 @Entity(tableName = "services")
data class Service @JvmOverloads constructor(
    @PrimaryKey val id: String,
    val name: String,
    val description: String,
    val parentId: String?,
    @Ignore val test: String? = null
)
  

Это заставит компилятор Kotlin сгенерировать конструктор с тремя параметрами и снова сделать Room счастливым.

Я использую обновление с помощью Gson converter для rest api, и я хотел бы поделиться pojos с room.

Вероятно, вам следует избегать этого и использовать два набора классов для моделирования ответа API и данных базы данных. Даже в этот начальный момент вам нужно сделать несколько «взломов», чтобы все заработало, если в будущем API или база данных изменятся, вам нужно будет внести более сложные изменения в большем количестве мест.

Комментарии:

1. Спасибо, это работает! Насчет того, что нужно иметь 2 набора классов, я понимаю вашу точку зрения, но я хотел бы иметь максимально чистый код. В любом случае, спасибо за совет.

Ответ №2:

На самом деле, вы можете сохранить неизменность с помощью одного класса и без @JvmOverloads хитрости. Вам просто нужен единственный видимый (для помещения) конструктор для сопоставления полей таблицы. Для вашего примера это было бы:

 @Entity(tableName = "services")
data class Service @Ignore constructor(
    @PrimaryKey val id: String,
    val name: String,
    val description: String,
    val parentId: String?,
    @Ignore val test: String
) {
    constructor(id: String, name: String, description: String, parentId: String?) : 
        this(id, name, description, parentId, /* some default value for test */)
}
  

Комментарии:

1. Спасибо, это идеальное решение! Почему это не является частью официальной документации ?!? (риторический вопрос)