从Firestore读取嵌套对象时出现“ RuntimeException:无法反序列化对象”的情况

时间:2019-02-05 12:18:18

标签: java android firebase google-cloud-firestore

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 / Android运行时:致命异常:主要       流程: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 :(得分:5)

您遇到以下错误:

  

无法将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类型的值,而不是类型的{{1 }}。

enter image description here

请参见,Himno属性具有引用。如果要获取该文档参考,只需使用:

himno

如果要使用:

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

然后将Himno himno=oficio.getHimno(); 属性更改为himno类型,而不是Himno类型。

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

enter image description here

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

还请注意以下句子:

  

Firestore中的自定义类必须包含

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

所以您的课程可能看起来像这样:

Spanned

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

编辑:

根据您的评论:

  

我将getTexto()的类型从Spanned更改为String,但是不起作用。

仅将public class Oficio { public Invitatorio invitatorio; public Himno himno; public Salmodia salmodia; public String oracion; public String responsorio; public OficioLecturas oficioLecturas; } 方法的返回类型从getTexto()更改为Spanned不会帮助您解决主要错误。

  

我不知道如何将himno属性更改为Himno类型,而不是DocumentReference。

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

Oficio

将返回类型为Himno himno=oficio.getHimno(); 的对象,而不是Himno。这是因为它是根据其数据类型进行存储的。

  

在RealTimeDatabase中,可以仅使用一个对象(Oficio par示例),并且可以从该对象获取对另一个嵌套对象的引用(Himno par示例)。

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

  

请参阅文档中名为“自定义对象”的部分

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

编辑2:

  

您是否告诉我,可以在Firestore中创建Himno类型的字段?

是的,您可以做到。您是如何在数据库中添加该引用的?用与添加引用相同的方式添加Himno对象。

  

我不知道我怎么能做到这一点。

通过创建类型为Himno的对象向数据库添加数据时,请以正确的方式设置Oficio对象。试试这个:

Himno
  

我误会了吗?

是的。为了能够管理Cloud Firestore数据库,您至少应具有以下基本知识:

  • 如何用Java创建对象
  • 如何设置对象属性
  • 如何将数据添加到Cloud Firestore
  • 什么是馆藏/文件
  • Firestore中允许的数据类型

答案 1 :(得分:3)

Firestore中的自定义类必须包含:

  • 公共默认构造函数(不带参数的构造函数)
  • 每个属性的公共吸气剂(相同类型)


这是你所缺少的

first_index = ((array<constant)*np.arange(len(array))).argmax()+1 类中的

texto没有公共吸气剂(相同类型)。您的吸气剂返回一个Himno


将其添加到Spanned类中:

Himno