Reputation: 4822
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?
Upvotes: 7
Views: 4850
Reputation: 372
Passing a org.json.JSONObject
instead of the com.google.gson.JsonObject
works just fine.
You don't need to use Maps on the firebase functions.
Upvotes: 0
Reputation: 3625
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.
Upvotes: 3
Reputation: 61
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;
}
}
}
Upvotes: 1