火力地堡 "Map while deserializing, but got a class java.util.ArrayList"

Firebase "Map while deserializing, but got a class java.util.ArrayList"

我只是在 android 上为我的项目试用 Firebase。

我遇到的问题是,每次拍摄快照并 "cast" 返回 POJO 我得到这个 -

"Map while deserializing, but got a class java.util.ArrayList"异常。

我一直在四处寻找,甚至使用 HashMap 更改了我所有的模型实现,根本没有任何 ArrayList,但仍然得到相同的结果。

这是我的模型:

  public class DevicesController {

        public DevicesCollection devices;
        public int numberOfport;
        String timerStatus;

        public DevicesController(){

            devices = new DevicesCollection();
            timerStatus = "UPDATED";
        }

        public DevicesController(int numberOfport){
            devices = new DevicesCollection();
            this.numberOfport = numberOfport;
            timerStatus = "UPDATED";
        }



        public ArrayList<Integer> getCurrentState(String in){
            ArrayList<Integer> currentState = new ArrayList<Integer>();
            for(int i = 0; i < numberOfport; i++){
                currentState.add(0);
            }
            Iterator it = this.getDevices().getAllDevices().entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry pair = (Map.Entry) it.next();
                Device temp =(Device)pair.getValue();
                if(temp.isOn()){
                    currentState.set(temp.getPort(),1);
                }else if(!temp.isOn()){
                    currentState.set(temp.getPort(),0);
                }
            }

            return currentState;
        }


        public String getStringCurrentState(String in){
            ArrayList<Integer> currentState = getCurrentState("");
            String temp ="";
            for(int i = 0; i < currentState.size();i++){
                temp.concat(""+currentState.get(i));
            }
            return temp;
        }

        public void updateToDb(){
            Global.dbMRoot.child("devicesController").setValue(this);
        }

        public DevicesCollection getDevices() {
            return devices;
        }

        public int getNumberOfport() {
            return numberOfport;
        }

    }

    public class Category {
        public String name;
        public HashMap<String,String> devicesId;
        public DeviceAlarm categoryAlarm;

        public Category(){

        }

        public Category(String name) {
            devicesId = new HashMap<String,String>();
            this.name = name;
        }

        public void addDevice(Device dev){
            devicesId.put(dev.getId(),dev.getId());
        }


        public void removeDevice(Device dev){
            devicesId.remove(dev.getId());
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public HashMap<String,String> getDevicesId() {
            return devicesId;
        }

        public void setDevicesId(HashMap<String,String> devicesId) {
            this.devicesId = devicesId;
        }

    }

public class Device {

    public String id;
    public int port;
    public String name;
    public boolean on;
    public  DeviceAlarm alarm;

    public Device(){

    }


    public Device(String id,String name){
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
        updateToDb();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        updateToDb();
        this.name = name;
    }

    public boolean isOn() {
        return on;
    }

    public void setOn(boolean on) {
        updateToDb();
        this.on = on;
    }

    public void updateToDb(){
        Global.dbMRoot.child("devicesController").child("devices").child("allDevice").child(""+id).setValue(this);
    }
    public DeviceAlarm getTimer() {

        return alarm;
    }


    public int getPort() {

        return port;
    }

    public void setPort(int port) {
        updateToDb();
        this.port = port;
    }

    public DeviceAlarm getAlarm() {
        return alarm;
    }

    public void setAlarm(DeviceAlarm alarm) {
        Global.dbMRoot.child("devicesController").child("timerStatus").setValue("CHANGED");
        this.alarm = alarm;
        updateToDb();
    }

    public void setAlarm(boolean active, Calendar timeOn, Calendar timeOff) {
        Global.dbMRoot.child("devicesController").child("timerStatus").setValue("CHANGED");
        DeviceAlarm temp = new DeviceAlarm();
        temp.setTimeOff(timeOff);
        temp.setTimeOn(timeOn);
        this.alarm = temp;
        updateToDb();
    }
}


package com.lucerna.afgadev.lucerna_maincontroller.Models;

import com.lucerna.afgadev.lucerna_maincontroller.Global;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * Created by aufa on 06/07/2016.
 */
public class DevicesCollection {

    public HashMap<String,Device> allDevices;
    public HashMap<String,Category>  categories;
    int lastId;

    public DevicesCollection(){
        categories = new HashMap<String,Category>();
        lastId = 0;
        allDevices = new HashMap<String, Device>();

    }

    public HashMap<String,Category> getCategories() {
        return categories;
    }

    public HashMap<String,Device> getAllDevices() {
        return allDevices;
    }

    public void addCategory(String name){
        categories.put(name,new Category(name));
    }

    public void removeCategory(String name) throws Exception{
        int index = -1;
        for(int i = 0; i< categories.size(); i++){
            if(categories.get(i).getName().equals(name)){
                index = 1;
            }
        }

        if(index == -1){
            throw new Exception("Category not found");
        }else{
            categories.remove(index);
        }

        updateToDB();

    }

    public void updateToDB(){
        Global.dbMRoot.child("devicesController").child("devices").setValue(this);
    }

    public Category findCategory(String name){
        Category temp = null;
        for(int i = 0; i< this.getCategories().size(); i++){
            if(this.getCategories().get(i).getName().equals(name)){
                temp = this.getCategories().get(i);
            }
        }
        return temp;
    }

    public void switchCategory(String name, boolean on){
        Category cat = findCategory(name);
        for(int i = 0; i < cat.getDevicesId().size();i++){

        }
    }


    public void addDevice(String name, int port){
        Device temp = new Device();
        temp.setPort(port);
        temp.setName(name);
        allDevices.put(""+lastId,temp);
        this.lastId++;
        Global.dbMRoot.child("devicesController").child("devices").child(""+lastId).setValue(allDevices.get(lastId));
    }

    public void removeDevice(int id){
        allDevices.remove(id);
        updateToDB();
    }

    public void setCategoryDevicesAlarm(DeviceAlarm da){

    }

}

样本JSON树GDrive

我仍然不知道为什么会发生这种情况,我已经重新检查以确保其中的 none 是一个 ArrayList(不过我知道 firebase 应该支持 arrayList)

感谢大家的评论和回答!

我有一个部分答案,但需要 Frank 的专业知识来解释到底发生了什么。

运行 9.2.0 版的发布代码,我观察到 allDevicesHashMap 存储为 JSON 数组:

public class DevicesCollection {

    public HashMap<String,Device> allDevices; <-- this is stored as array
    public HashMap<String,Category>  categories;
    int lastId;

这在 Aufa 发布的 JSON 中可见:

{
  "devicesController" : {
    "devices" : {
      "allDevices" : [ { <-- note bracket
        "name" : "",
        "on" : true,
        "port" : 0
      }, {

这似乎是因为 allDevices 的元素的键是整数形式的字符串。这是向 allDevices:

的映射添加条目的代码
public void addDevice(String name, int port){
    Device temp = new Device();
    temp.setPort(port);
    temp.setName(name);
    allDevices.put(""+lastId,temp); <-- Note that lastId is an integer
    this.lastId++;
    Global.dbMRoot.child("devicesController").child("devices").child(""+lastId).setValue(allDevices.get(lastId));
}

如果将此代码修改为使用非整数格式的字符串键,例如:

allDevices.put("ID"+lastId,temp);

然后把地图写成地图,可以用

读取
getValue(DevicesCollection.class);

如果您是这样映射的:

    basketRef.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            if(dataSnapshot.value==null || dataSnapshot.value!!.equals(""))
                Enums.userBasket=UserItem()
            else
                Enums.userBasket = dataSnapshot.getValue(UserItem::class.java)
        }

        override fun onCancelled(p0: DatabaseError) {
            // Failed to read value
            Log.d(TAG, "Error= "+p0.message)
        }

    })

并且在 firebase 设备中 ids 元素子元素如 (-1:"",-2:"")

Firebase Android SDK 认为这是一个 ArrayList 而不是 Map 对象。

下面的代码对我来说工作正常。我不能使用上面的代码。

Enums.userBasket=UserItem()
    basketRef.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            if(dataSnapshot.value==null || dataSnapshot.value!!.equals(""))

            else{
                if(dataSnapshot.child("books")!=null){
                    dataSnapshot.child("books").children.forEach {
                        Enums.userBasket!!.books[it.key.toString()] =it.value.toString()
                    }
                }
                if(dataSnapshot.child("cards")!=null){
                    dataSnapshot.child("cards").children.forEach {
                        Enums.userBasket!!.cards[it.key.toString()] =it.value.toString()
                    }
                }
                if(dataSnapshot.child("exams")!=null){
                    dataSnapshot.child("exams").children.forEach {
                        Enums.userBasket!!.exams[it.key.toString()] =it.value.toString()
                    }
                }
            }

        }

        override fun onCancelled(p0: DatabaseError) {
            // Failed to read value
            Log.d(TAG, "Error= "+p0.message)
        }

    })

我的 UserItem class:

 @IgnoreExtraProperties
data class UserItem(
    var books:MutableMap<String,String> = HashMap(),//id,value
    var cards:MutableMap<String,String> = HashMap(),//id,value
    var exams:MutableMap<String,String> = HashMap()//id,value
)

或者你可以看看这个 link。

我也遇到了同样的错误。但后来我才知道,起初,我在 Note.kt 数据 class 中使用 List 的 tags 变量并将其存储在 firestore 文档中,但后来我更改了相同的变量名称 tags 使用 Map 并尝试从 firestore 获取数据。在 firestore 中,我的名称 tags 与 List 和 Map 相同,因此在从 firestore 获取数据时出现错误。当我删除集合并再次添加数据时,我的问题就解决了。

Note.kt

 data class Note(
 //val tags:List<String>? = null, //first with tags variable 
 val tags:Map<String,Any>? = null, //second with same tags variable

)