Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase: passing data to cloudfunction results in: Object cannot be encoded in JSON

I try to call a cloud function and pass some data. My data is of type Map<String, Object> and inside it has again some nested Map<String, Object>. When trying to call my function with this:

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

I get this error:

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)

When printing my data object it looks like this:

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

I tried the following: I tried packing an array instead of a Map inside my data-object. => Did not work.

I tried to convert my data into a json myself and send it, this also didn't work.

I did the follwoing:

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

which restulted in a nice formatted 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"}

But I also tried to call my function with a hardcoded JSON which did not work either.

I can't figure out what I am doing wrong. Does anyone know?

like image 414
progNewbie Avatar asked May 02 '18 15:05

progNewbie


2 Answers

The problem is you are actually passing array of Map objects.

As Frederik Byl shows the source code of Functions SDK for Android, it won't accept array type. It accepts Map or List Java Collection object.

So you must change your [Ljava.util.Map; to List<Map> type.

Plus, actully Firestore uses Protobuf for core dataset. You can find more information at here how they encode or decode json with Protobuf data.

like image 142
wonsuc Avatar answered Oct 19 '22 23:10

wonsuc


I think you should create and pass a JSONObject out of your data object. Not a string or the data object: like this:

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

because:

  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;
                    }
                }
            }
like image 26
Frederik Byl Avatar answered Oct 19 '22 23:10

Frederik Byl