从Firestore读取嵌套对象时出现"RuntimeException:无法反序列化对象"

A. *_*ano 7 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": {
  ... 
Run Code Online (Sandbox Code Playgroud)


Oficio:

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;
    }
// ...
}
Run Code Online (Sandbox Code Playgroud)


Himno:

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;
    }
    //...
}
Run Code Online (Sandbox Code Playgroud)


我尝试过的:

    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
        }
    });
Run Code Online (Sandbox Code Playgroud)


问题:

我无法将该属性himno视为自定义类'Himno'.当我尝试,我得到一个"RuntimeException的"即使我评论这行:Himno himno=oficio.getHimno();.然而,我可以将属性oracion放入相应的变量中.


堆栈跟踪:

E/AndroidRuntime:FATAL EXCEPTION:main进程:org.my.app,PID:10532 java.lang.RuntimeException:无法反序列化对象.无法将com.google.firebase.firestore.DocumentReference类型的对象转换为在com.google.firebase.firestore.util.CustomClassMapper.deserializeError中键入org.my.app.model.Himno(在字段'himno'中找到) 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)at at 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.fire.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)at com.google.firebase.firestore.util.CustomClassMapper $ BeanMapper.deserialize(com.google .firebase:火力-@@的FireStore 1 7.1.2:674)com.google.firebase.fireI.CustomClassMapper上的com.google.firebase.firestore.util.CustomClassMapper.convertBean(com.google.firebase:firebase-firestore @@ 17.1.2:503) .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) :火力点,公司的FireStore @@ 17.1.2:183)

Ale*_*amo 5

您收到以下错误:

无法将com.google.firebase.firestore.DocumentReference类型的对象转换为类型org.my.app.model.Himno(在字段'himno'中找到)

因为您正在尝试将DocumentReference对象转换为Himno对象.Java中没有办法实现这一点,因为它们之间没有继承关系.

您尝试从以下位置获取的文档:

db.collection("liturgia").document("breviario").collection("oficio").document("20190204");
Run Code Online (Sandbox Code Playgroud)

是类型Oficio,所以下面的代码行:

Oficio oficio = documentSnapshot.toObject(Oficio.class);
Run Code Online (Sandbox Code Playgroud)

会工作得很好.问题是当你试图获得Himno嵌套在你的Oficio类下面的对象时:

Himno himno=oficio.getHimno();
Run Code Online (Sandbox Code Playgroud)

而且,由于你这不会在你的方式做工作,himno在文档中属性保存的值类型是DocumentReference不是类型Himno.

在此输入图像描述

看,该himno属性有参考.如果您想获得该文档参考,只需使用:

DocumentReference documentReference = documentSnapshot.getDocumentReference("himno");
Run Code Online (Sandbox Code Playgroud)

如果你想使用:

Himno himno=oficio.getHimno();
Run Code Online (Sandbox Code Playgroud)

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

你的代码中的另一个问题,也就是@Anees在他的aswer中指出,该getTexto()方法应该返回一个String而不是一个Spanned对象,因为这是存储在数据库中的方式.

在此输入图像描述

看,该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;
}
Run Code Online (Sandbox Code Playgroud)

没有任何构造函数,设置器或getter.更多信息在这里.

编辑:

根据你的评论:

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

仅改变你的返回类型getTexto(),从方法SpannedString不会帮你解决的主要错误.

我不明白我怎么能把himno属性改为Himno类型而不是DocumentReference.

您还没有分享将数据添加到数据库的方式,但实际上非常简单.首先,himno从这些文档中删除该属性.然后,当你添加一个新文档时,不是添加一个,而是添加一个DocumentReference类型的对象Himno,因为我也看到你已经在你的Oficio类中声明了.这也意味着,当您使用以下代码行时:

Himno himno=oficio.getHimno();
Run Code Online (Sandbox Code Playgroud)

Himno将返回类型的对象而不是a DocumentReference.这是因为它相应地存储在其数据类型中.

在RealTimeDatabase中,只能获取一个对象(Oficio par示例),并且从该对象中我可以获得对另一个嵌套对象的引用(Himno par example).

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

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

是的,我明白了.这就是为什么我告诉你根据它存储的数据类型获取数据的原因.因此,如果您将数据存储为a DocumentReference,请根据它获取.如果你想把它作为a Himno,首先将它存储为a Himno,然后相应地得到它.

EDIT2:

你是否告诉我,在Firestore中可以创建一个Himno类型的领域?

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

我不明白我是如何做到这一点的.

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

Oficio oficio = new Oficio();
Himno himno = new Himno();
himno.setTexto("Your Text");
oficio.setHimno(himno);
docRef.set(oficio);
Run Code Online (Sandbox Code Playgroud)

我误解了它的事情?

是.为了能够管理Cloud Firestore数据库,您应该至少基本了解:

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

  • @Anees来自文档的句子是正确的****如果您使用私有字段,那应该在那里提到.如果你有公共字段,则不需要构造函数,getter或setter.请参阅我的答案的最后部分中的示例.这样的课程将完美无缺.你也应该尝试一下.谢谢你的聊天:) (2认同)
  • "这应该在那里提到"是的,你是对的. (2认同)

Ber*_*yle 4

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

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


这就是你所缺少的

texto 来自该类Himno没有公共 getter(相同类型)。你的 getter 返回一个Spanned.


将其添加到类中Himno

public String getTexto() {
    return this.textTo;
}
Run Code Online (Sandbox Code Playgroud)