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:

java - 从Firestore读取嵌套对象时"RuntimeException: Could not deserialize object"-LMLPHP
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:

java - 从Firestore读取嵌套对象时"RuntimeException: Could not deserialize object"-LMLPHP
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放入相应的变量中。

堆栈跟踪:

最佳答案

您收到以下错误:



因为您正在尝试将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类型的,因此这将无法以您的方式进行。

java - 从Firestore读取嵌套对象时&#34;RuntimeException: Could not deserialize object&#34;-LMLPHP

看到,himno属性有一个引用。如果要获取该文档引用,只需使用:
DocumentReference documentReference = documentSnapshot.getDocumentReference("himno");

如果要使用:
Himno himno=oficio.getHimno();

然后将himno属性更改为Himno类型,而不是DocumentReference类型。

您的代码中的另一个问题(正如@Anees在他的问题中所指出的那样)是getTexto()方法应该返回String而不是Spanned对象,因为这是存储在数据库中的方式。

java - 从Firestore读取嵌套对象时&#34;RuntimeException: Could not deserialize object&#34;-LMLPHP

参见,texto属性包含一个String而不是Spanned。但这是而不是发生错误的原因。

还请注意,以下句子:



是不正确的!公共(public)无参数构造函数和公共(public)获取者都没有必要。

因此,您的类(class)可能看起来像这样:
public class Oficio {
    public Invitatorio invitatorio;
    public Himno himno;
    public Salmodia salmodia;
    public String oracion;
    public String responsorio;
    public OficioLecturas oficioLecturas;
}

根本没有任何构造函数,setter或getter。更多信息 here

编辑:

根据您的评论:



仅将getTexto()方法的返回类型从Spanned更改为String不会帮助您解决主要错误。



您尚未共享将数据添加到数据库的方式,但实际上非常简单。首先,从那些文档中删除该himno属性。然后,当您添加一个新文档时,而不是添加一个DocumentReference,而是添加一个Himno类型的对象,正如我还看到的那样,您已经在Oficio类中进行了声明。这也意味着,当您使用以下代码行时:
Himno himno=oficio.getHimno();

将返回Himno类型的对象,而不是DocumentReference。这是因为它根据其数据类型进行存储。



这也可以在Cloud Firestore中完成,但是您需要根据数据库中存在的属性的数据类型来获取数据。如果您的属性类型为DocumentReference,则不能将其作为Himno类型获得,除非您像这样添加它。



是的,我明白了。这就是为什么我告诉您根据存储的数据类型获取数据的原因。因此,如果您将数据存储为DocumentReference,请根据它进行获取。如果要以Himno的形式获取它,请首先将其以Himno的形式存储,然后相应地获取它。

编辑2:



是的,您可以做到。您是如何在数据库中添加该引用的?以与添加引用相同的方式添加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中的允许数据类型
  • 10-05 21:21