Как десериализировать подкласс в Firebase, используя getValue (Subclass.class)

Я использую новый firebase sdk для android и использую реальную функцию базы данных. Когда я использую getValue(simple.class), все в порядке. Но когда я хочу разобрать класс, который является подклассом, все атрибуты материнского класса null, и я имею этот тип ошибки:

Нет setter/field для имени, найденного в классе uk.edume.edumeapp.TestChild

public class TestChild  extends TestMother {

    private String childAttribute;

    public String getChildAttribute() {
        return childAttribute;
    }
}

public class TestMother {

    protected String motherAttribute;

    protected String getMotherAttribute() {
        return motherAttribute;
    }
}

эта функция

snapshot.getValue(TestChild.class);

motherAttribute атрибут null, и я получаю

Нет setter/field для атрибута motherAttribute, найденного в классе uk.edume.edumeapp.TestChild

Json, который я разбираю:

{
  "childAttribute" : "attribute in child class",
  "motherAttribute" : "attribute in mother class"
}

Ответ 1

Firebaser здесь

Это известная ошибка в некоторых версиях Firebase Database SDK для Android: наш сериализатор/десериализатор рассматривает свойства/поля только для объявленного класса.

Сериализация унаследованных свойств из базового класса отсутствует в версиях с 9.0 до 9.6 (iirc) SDK Firebase для Android. Он был добавлен обратно в версии с тех пор.

Обход

Тем временем вы можете использовать Jackson (который SDK Firebase 2.x использует под капотом), чтобы заставить модель наследования работать.

Обновить: здесь приведен фрагмент того, как вы можете читать JSON в своем TestChild:

public class TestParent {
    protected String parentAttribute;

    public String getParentAttribute() {
        return parentAttribute;
    }
}
public class TestChild  extends TestParent {
    private String childAttribute;

    public String getChildAttribute() {
        return childAttribute;
    }
}

Вы заметите, что я сделал публикацию getParentAttribute() общедоступной, потому что рассматриваются только общедоступные поля/геттеры. С этим изменением этот JSON:

{
  "childAttribute" : "child",
  "parentAttribute" : "parent"
}

Становится читаемым с помощью:

ObjectMapper mapper = new ObjectMapper();
GenericTypeIndicator<Map<String,Object>> indicator = new GenericTypeIndicator<Map<String, Object>>() {};
TestChild value = mapper.convertValue(dataSnapshot.getValue(indicator), TestChild.class);

GenericTypeIndicator немного странно, но, к счастью, это волшебное заклинание, которое можно скопировать/вставить.

Ответ 2

Это, по-видимому, окончательно было исправлено в release 9.6.

Исправлена ​​ошибка, при которой передача производного класса в DatabaseReference # setValue() неправильно сохранила свойства суперкласса.

Ответ 3

для

Нет setter/field для атрибута motherAttribute, найденного в классе uk.edume.edumeapp.TestChild

установить сеттер для класса TestChild:

 public class  TestMother {

     private String motherAttribute;

     public String getMotherAttribute() {
         return motherAttribute;
     }

     //set
     public void setMotherAttribute(String motherAttribute) {
         this.motherAttribute= motherAttribute;
     }
 }

Ответ 4

Отметьте https://firebase.google.com/support/guides/firebase-android

говорится

"Если в вашем JSON есть дополнительное свойство, не входящее в ваш Java-класс, вы увидите это предупреждение в файлах журнала: W/ClassMapper: Нет setter/field для ignoreThisProperty, найденных в классе com.firebase.migrationguide. ChatMessage"

Blockquote

Вы можете избавиться от этого предупреждения, разместив в своем классе аннотацию @IgnoreExtraProperties. Если вы хотите, чтобы база данных Firebase вела себя так, как в SDK 2.x, и генерирует исключение, если есть неизвестные свойства, вы можете поместить аннотацию @ThrowOnExtraProperties в свой класс.

Blockquote