«RuntimeException: Не удалось десериализовать объект» при чтении вложенного объекта из Firestore - PullRequest
0 голосов
/ 05 февраля 2019

Структура JSON:

{
    "breviario": {
        "metaLiturgia": {
                "fecha"  : "Martes  5 de febrero del 2019",
                "tiempo" : "PROPIO DE LOS SANTOS",
                "semana"   : "",
                "mensaje": "",
                "salterio": "",
                "color":0,
                "meta": ""
        },
        "santo": {
                "nombre": "Santa Águeda, virgen y mártir",
                "vida": "Padeció el martirio en Catania (Sicilia), probablemente en la persecución de Decio. Desde la antigüedad su culto se extendió por toda la Iglesia y su nombre fue introducido en el Canon romano."
        },

        "oficio": {
            "himno": {
                "texto": "Testigos de amor~de Cristo Señor,~mártires santos.§Rosales en flor~de Cristo el olor,~mártires santos.§Palabras en luz~de Cristo Jesús,~mártires santos.§Corona inmortal~del Cristo total,~mártires santos. Amén."
            },
            "salmodia": {
  ... 


Oficio:

Structure of Ofcio

public class Oficio {
    private Invitatorio invitatorio;
    private Himno himno;
    private Salmodia salmodia;
    private String oracion;
    private String responsorio;
    private OficioLecturas oficioLecturas;
    public Oficio () {}

    public Himno getHimno() {
        return himno;
    }

    public void setHimno(Himno himno) {
        this.himno = himno;
    }
// ...
}


Himno:

Structure of Himno

public class Himno {
    private String texto;
    public Himno () {}

    public Spanned getTexto() {
        Spanned str = Utils.fromHtml(Utils.getFormato(texto));
        return str;
    }

    public void setTexto(String texto) {
        this.texto = texto;
    }
    //...
}


Что япробовал:

    DocumentReference docRef = db.collection("liturgia").document("breviario")
            .collection("oficio").document("20190204");
    docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
        @Override
        public void onSuccess(DocumentSnapshot documentSnapshot) {
            Oficio oficio = documentSnapshot.toObject(Oficio.class);
            Himno himno=oficio.getHimno();
            Log.d(TAG,oficio.getOracion().toString()); //Correct
        }
    });


Проблема:

Я не могу прочитать свойство himno как пользовательский класс Himno.При попытке получить «RuntimeException», даже если я прокомментирую строку: Himno himno=oficio.getHimno();.Однако я могу получить свойство oracion в соответствующую переменную.


Трассировка стека:

E / AndroidRuntime: FATAL EXCEPTION: main Process: org.my.app, PID: 10532 java.lang.RuntimeException: Не удалось десериализовать объект.Не удается преобразовать объект типа com.google.firebase.firestore.DocumentReference в тип org.my.app.model.Himno (находится в поле 'himno') на com.google.firebase.firestore.util.CustomClassMapper.deserializeError (com.google.firebase: firebase-firestore @@ 17.1.2: 524) по адресу com.google.firebase.firestore.util.CustomClassMapper.convertBean (com.google.firebase: firebase-firestore @@ 17.1.2: 505) по адресуcom.google.firebase.firestore.util.CustomClassMapper.deserializeToClass (com.google.firebase: firebase-firestore @@ 17.1.2: 242) по адресу com.google.firebase.firestore.util.CustomClassMapper.deserializeToType (com.google.firebase: firebase-firestore @@ 17.1.2: 180) на com.google.firebase.firestore.util.CustomClassMapper.access $ 200 (com.google.firebase: firebase-firestore @@ 17.1.2: 53) на com.google.firebase.firestore.util.CustomClassMapper $ BeanMapper.deserialize (com.google.firebase: firebase-firestore @@ 17.1.2: 700) по адресу com.google.firebase.firestore.util.CustomClassMapper $ BeanMapper.deserialize (com.google.firebase: firebase-Firestore @@ 17.1.2: 674) на com.google.firebase.firestore.util.CustomClassMapper.convertBean (com.google.firebase: firebase-firestore @@ 17.1.2: 503) на com.google.firebase.firestore.util.CustomClassMapper.deserializeToClass (com.google.firebase: firebase-firestore @@ 17.1.2: 242) по адресу com.google.firebase.firestore.util.CustomClassMapper.convertToCustomClass (com.google.firebase: firebase-firestore @@ 17.1.2:97) на com.google.firebase.firestore.DocumentSnapshot.toObject (com.google.firebase: firebase-firestore @@ 17.1.2: 203) на com.google.firebase.firestore.DocumentSnapshot.toObject (com.google.firebase: firebase-firestore @@ 17.1.2: 183)

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

Вы получаете следующую ошибку:

Невозможно преобразовать объект типа com.google.firebase.firestore.DocumentReference в тип org.my.app.model.Himno (находится в поле'himno')

Поскольку вы пытаетесь преобразовать объект DocumentReference в объект Himno.В Java нет способа достичь этого, так как между ними нет отношений наследования.

Документ, который вы пытаетесь получить из следующего местоположения:

db.collection("liturgia").document("breviario").collection("oficio").document("20190204");

Типа Oficio, поэтому следующая строка кода:

Oficio oficio = documentSnapshot.toObject(Oficio.class);

Будет отлично работать.Проблема в том, что вы пытаетесь получить объект Himno, который вложен в ваш класс Oficio, например:

Himno himno=oficio.getHimno();

И это не будет работать так, как вы делаете, так как ваш himnoсвойство внутри документа содержит значение типа DocumentReference и , а не типа Himno.

enter image description here

См.свойство himno имеет ссылку.Если вы хотите получить ссылку на этот документ, просто используйте:

DocumentReference documentReference = documentSnapshot.getDocumentReference("himno");

Если вы хотите использовать:

Himno himno=oficio.getHimno();

Затем измените свойство himno на тип Himnoа не DocumentReference.

Другая проблема в вашем коде, о которой @Anees также указал в своем ответе, заключается в том, что метод getTexto() должен возвращать String, а не Spanned объект, потому что этокаким образом хранится в базе данных.

enter image description here

Смотрите, свойство texto содержит String, а не Spanned.Но это не причина возникновения вашей ошибки.

Обратите также внимание, что следующее предложение:

Пользовательские классы в Firestore должны содержат

Неверно!Нет необходимости ни в общедоступном конструкторе без аргументов, ни в общедоступных методах получения.

Так что ваш класс может выглядеть просто так:

public class Oficio {
    public Invitatorio invitatorio;
    public Himno himno;
    public Salmodia salmodia;
    public String oracion;
    public String responsorio;
    public OficioLecturas oficioLecturas;
}

Без каких-либо конструкторов, сеттеров или геттеровсовсем.Больше информации здесь .

Редактировать:

Согласно вашему комментарию:

Я изменил тип getTexto () с Spanned на String, но он не работает.

Изменение только типа возврата вашего getTexto() метода с Spanned на String не поможет вамрешить основную ошибку.

Я не понимаю, как я могу изменить свойство himno, чтобы иметь тип Himno, а не DocumentReference.

Вы не поделилисьТо, как вы добавляете данные в базу данных, но на самом деле все очень просто.Сначала удалите это свойство himno из этих документов.Затем, когда вы добавляете новый документ, вместо добавления DocumentReference, добавьте объект типа Himno, поскольку я также вижу, что вы объявили в своем классе Oficio.Это также означает, что когда вы будете использовать следующую строку кода:

Himno himno=oficio.getHimno();

Будет возвращен объект типа Himno, а не DocumentReference.Это потому, что он хранится в соответствии с его типом данных.

В RealTimeDatabase возможно взять только один объект (пример Oficio) и из этого объекта я могу получить ссылки на другой вложенный объект (Himno parпример).

Это также можно сделать в Cloud Firestore, но вам нужно получить данные в соответствии с типом данных вашего свойства, которое существует в базе данных.Если ваше свойство имеет тип DocumentReference, вы не можете получить его как тип Himno, если не добавите его следующим образом.

См. Раздел «Пользовательские объекты» в документации * 1121.*

Да, понятно.Вот почему я сказал вам, чтобы получить данные в соответствии с типом данных, которые они хранятся.Так что если у вас есть данные, хранящиеся как DocumentReference, получите их в соответствии с нимиЕсли вы хотите получить его как Himno, сначала сохраните его как Himno, а затем получите соответственно.

Edit2:

Вы говорите мне, что можете создать поле типа Химно в Firestore?

Да, вы можете сделать это.Как вы добавили эту ссылку в базу данных?Таким же образом вы добавили эту ссылку, добавив объект Himno.

Я не понимаю, как мне этого добиться.

Когда вы добавляете данные вбазу данных, создав объект типа Oficio, правильно установите объект Himno.Попробуйте это:

Oficio oficio = new Oficio();
Himno himno = new Himno();
himno.setTexto("Your Text");
oficio.setHimno(himno);
docRef.set(oficio);

Я не совсем понимаю, что с этим связано?

Да.Чтобы иметь возможность управлять базой данных Cloud Firestore, вы должны иметь, по крайней мере, базовые знания о:

  • Как создавать объекты в Java
  • Как установить свойства объекта
  • КакДобавить данные в Cloud Firestore
  • Что такое коллекции / документы
  • Разрешенный тип данных в Firestore
0 голосов
/ 08 февраля 2019

Пользовательские классы в Firestore должны содержать:

  • Открытый конструктор по умолчанию (конструктор, не имеющий аргументов)
  • Публичные методы получения (того же типа) для каждого свойства


Вот то, что вам не хватает

texto из класса Himno не имеет публичного получателя (того же типа).Ваш получатель возвращает Spanned.


Добавьте это к классу Himno:

public String getTexto() {
    return this.textTo;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...