Firebase:将数据传递给 cloudfunction 导致:对象无法用 JSON 编码

Posted

技术标签:

【中文标题】Firebase:将数据传递给 cloudfunction 导致:对象无法用 JSON 编码【英文标题】:Firebase: passing data to cloudfunction results in: Object cannot be encoded in JSON 【发布时间】:2018-10-12 18:27:51 【问题描述】:

我尝试调用云函数并传递一些数据。我的数据是Map<String, Object> 类型,里面又嵌套了一些Map<String, Object>。当试图用这个调用我的函数时:

getHttpsCallable(function).call(data)...

我得到这个错误:

Cloud Function Exception:                                                         
java.lang.IllegalArgumentException: Object cannot be encoded in JSON: [Ljava.util.Map;@42896770
 at com.google.firebase.functions.Serializer.encode(Serializer.java:136)
 at com.google.firebase.functions.Serializer.encode(Serializer.java:77)
 at com.google.firebase.functions.FirebaseFunctions.call(FirebaseFunctions.java:255)
 at com.google.firebase.functions.FirebaseFunctions.access$100(FirebaseFunctions.java:34)
 at com.google.firebase.functions.FirebaseFunctions$2.then(FirebaseFunctions.java:233)
 at com.google.firebase.functions.FirebaseFunctions$2.then(FirebaseFunctions.java:225)
 at com.google.android.gms.tasks.zzd.run(Unknown Source)
 at android.os.Handler.handleCallback(Handler.java:733)
 at android.os.Handler.dispatchMessage(Handler.java:95)
 at android.os.Looper.loop(Looper.java:146)
 at android.app.ActivityThread.main(ActivityThread.java:5653)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:515)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
 at dalvik.system.NativeStart.main(Native Method)

打印我的数据对象时,它看起来像这样:

items=[Ljava.util.Map;@42896770, element1=OzNGHzHeq6av03hRmMJ6, time=Sun May 05 04:40:00 MEZ 3918

我尝试了以下方法: 我尝试在我的数据对象中打包一个数组而不是一个 Map。 => 没用。

我自己尝试将我的数据转换成json并发送,这也没有用。

我做了以下操作:

Gson gson = new Gson();
String dataJSON = gson.toJson(data);

最终生成了格式良好的 JSON:

"items":["count":1,"itemId":"94To3bKnxoWzayLdy55I","count":3,"itemId":"fkNtIUxbfg5GhLJy2Dma","count":1,"itemId":"sDYTp7cpQTRfWuI6CSaK","count":1,"itemId":"qGGl5U0qihHnMzhBMjyb","options":["2.0","1.0","1.1","0.0"],"count":1,"itemId":"qGGl5U0qihHnMzhBMjyb","options":["2.0","1.0","1.1","0.1"],"count":1,"itemId":"qGGl5U0qihHnMzhBMjyb","options":["2.0","1.0","1.1","0.2"],"count":1,"itemId":"qGGl5U0qihHnMzhBMjyb","options":["2.3","1.0","1.1","0.1"]],"storeId":"OzNGHzHeq6av03hRmMJ6","pickupTime":"May 5, 3918 4:40:00 AM"

但我也尝试使用硬编码的 JSON 调用我的函数,但它也不起作用。

我不知道我做错了什么。有人知道吗?

【问题讨论】:

也许使用 Gson 库 mkyong.com/java/… 或 github.com/google/gson @RenaudTarnec 我做到了。我在我的方法中使用它来发送预构建 json。 items=[Ljava.util.Map;@42896770,... 不看 JSON... 是的。当只是尝试我在最初的问题文本中所说的内容时,它看起来像这样。我刚刚在我的问题中告诉我,我还尝试了一些其他的东西,包括用 gson 生成一个 json。 你能分享你用 Gson 写的代码来将你的 java 对象转换成 JSON 吗? 【参考方案1】:

问题是您实际上传递了arrayMap 对象。

由于 Frederik Byl 显示了 Functions SDK for Android 的源代码,它不接受数组类型。它接受MapList Java Collection 对象。

因此,您必须将您的 [Ljava.util.Map; 类型更改为 List<Map>

另外,实际上 Firestore 使用 Protobuf 作为核心数据集。您可以在here 找到更多信息,他们如何使用 Protobuf 数据对 json 进行编码或解码。

【讨论】:

【参考方案2】:

我认为您应该从数据对象中创建并传递一个 JSONObject。不是字符串或数据对象: 像这样:

 Gson gson = new Gson();
    String jsonString = gson.toJson(data);
    JSONObject jsonObj = null;
    try 
         jsonObj = new JSONObject(jsonString);
     catch (JSONException e) 
        e.printStackTrace();
    

因为:

  public Object encode(Object obj) 
    if (obj != null && obj != JSONObject.NULL) 
        JSONObject result;
        if (obj instanceof Long) 
            result = new JSONObject();

            try 
                result.put("@type", "type.googleapis.com/google.protobuf.Int64Value");
                result.put("value", obj.toString());
                return result;
             catch (JSONException var9) 
                throw new RuntimeException("Error encoding Long.", var9);
            
         else if (obj instanceof Number) 
            return obj;
         else if (obj instanceof String) 
            return obj;
         else if (obj instanceof Boolean) 
            return obj;
         else if (obj instanceof JSONObject) 
            return obj;
         else if (obj instanceof JSONArray) 
            return obj;
         else 
            Object o;
            String key;
            Object value;
            Iterator keys;
            if (obj instanceof Map) 
                result = new JSONObject();
                Map<?, ?> m = (Map)obj;
                keys = m.keySet().iterator();

                while(keys.hasNext()) 
                    o = keys.next();
                    if (!(o instanceof String)) 
                        throw new IllegalArgumentException("Object keys must be strings.");
                    

                    key = (String)o;
                    value = this.encode(m.get(o));

                    try 
                        result.put(key, value);
                     catch (JSONException var10) 
                        throw new RuntimeException(var10);
                    
                

                return result;
             else 
                JSONArray result;
                if (obj instanceof List) 
                    result = new JSONArray();
                    List<?> l = (List)obj;
                    keys = l.iterator();

                    while(keys.hasNext()) 
                        o = keys.next();
                        result.put(this.encode(o));
                    

                    return result;
                 else 
                    JSONObject wrapped;
                    if (obj instanceof JSONObject) 
                        result = new JSONObject();
                        wrapped = (JSONObject)obj;
                        keys = wrapped.keys();

                        while(keys.hasNext()) 
                            String k = (String)keys.next();
                            if (!(k instanceof String)) 
                                throw new IllegalArgumentException("Object keys must be strings.");
                            

                            key = k;
                            value = this.encode(wrapped.opt(k));

                            try 
                                result.put(key, value);
                             catch (JSONException var11) 
                                throw new RuntimeException(var11);
                            
                        

                        return result;
                     else if (!(obj instanceof JSONArray)) 
                        if (obj instanceof Date) 
                            String utc = this.dateFormat.format((Date)obj);
                            wrapped = new JSONObject();

                            try 
                                wrapped.put("@type", "type.googleapis.com/google.protobuf.Timestamp");
                                wrapped.put("value", utc);
                                return wrapped;
                             catch (JSONException var12) 
                                throw new RuntimeException("Error encoding Date.", var12);
                            
                         else 
                            throw new IllegalArgumentException("Object cannot be encoded in JSON: " + obj);
                        
                     else 
                        result = new JSONArray();
                        JSONArray l = (JSONArray)obj;

                        for(int i = 0; i < l.length(); ++i) 
                            o = l.opt(i);
                            result.put(this.encode(o));
                        

                        return result;
                    
                
            

【讨论】:

【参考方案3】:

传递 org.json.JSONObject 而不是 com.google.gson.JsonObject 就可以了。

您无需在 firebase 函数上使用地图。

【讨论】:

以上是关于Firebase:将数据传递给 cloudfunction 导致:对象无法用 JSON 编码的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据传递给BottomSheetDialogFragment [重复]

将数据传递给 viewController

将数据传递给服务 - android?

vue js将数据传递给组件

如何通过数组将数据传递给表格视图?

意图不将数据传递给 AlarmManager 的 BroadcastReceiver