Java – Mobile Backend Starter subscribeToCloudMessage will not work

Mobile Backend Starter subscribeToCloudMessage will not work… here is a solution to the problem.

Mobile Backend Starter subscribeToCloudMessage will not work

When I use the subscribeToCloudMessage() function with CloudBackendMessaging.TOPIC_ID_BROADCAST as the topicId, as I did in CloudBackendFragment.java, everything works fine, but when I provide my own string for the function, I get this message:

Error:

m.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request

"code": 400,
"errors": [
  {
    "domain": "global",
    "message": "SubscriptionIDs: String properties must be 500 characters or less.  Instead, use com.google.appengine.api.datastore.Text, which can store strings of any length.",
    "reason": "badRequest"
  }
],
"message": "SubscriptionIDs: String properties must be 500 characters or less.  Instead, use com.google.appengine.api.datastore.Text, which can store strings of any length."

at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:111)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:38)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1042)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.google.cloud.backend.core.CloudBackend.list(CloudBackend.java:314)
at com.google.cloud.backend.core.CloudBackendAsync.access$8(CloudBackendAsync.java:1)
at com.google.cloud.backend.core.CloudBackendAsync$9.callBackend(CloudBackendAsync.java:270)
at com.google.cloud.backend.core.CloudBackendAsync$9.callBackend(CloudBackendAsync.java:1)
at com.google.cloud.backend.core.CloudBackendAsync$BackendCaller.run(CloudBackendAsync.java:402)

Solution

This error message indicates that the value of the property SubscriptionIDs, which you can find under the _DeviceSubscription type in the data store, exceeds the 500 Unicode character limit. Read docs for reference.

From the documentation:

For text strings and unencoded binary data (byte strings), the
Datastore supports two value types:

  1. Short strings (up to 500 Unicode characters or bytes) are indexed
    and can be used in query filter conditions and sort orders.
  2. Longstrings (up to 1 megabyte) are not indexed and cannot be used in query filters and sort orders.

This happens because MBS tries to write all subscriptions to a single property.

So, to overcome this problem, we need to enter Text instead of String noopener nofollow”>MBS backend source code for the SubscriptionIDs property. To do this, you need to make the following changes in the DeviceSubscription.java class:

To set the Text property, replace this line of code:

deviceSubscription.setProperty(PROPERTY_SUBSCRIPTION_IDS, this.gson.toJson(subscriptions));

With this line:

deviceSubscription.setProperty(PROPERTY_SUBSCRIPTION_IDS, new Text(this.gson.toJson(subscriptions)));

Get the Text property from the data store:

  1. Replace this line:

    String subscriptionString = (String) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
    

    With this:

    Text text = (Text) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
        String subscriptionString = text.getValue();
    
  2. Replace this line:

    String ids = (String) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
    

    With this:

    Text text = (Text) deviceSubscription.getProperty(PROPERTY_SUBSCRIPTION_IDS);
          String ids = text.getValue();
    
  3. Replace this line:

    String[] ids = new Gson().fromJson((String) entity.getProperty(PROPERTY_SUBSCRIPTION_IDS),
                String[].class);
    

    With this:

    Text text = (Text) entity.getProperty(PROPERTY_SUBSCRIPTION_IDS);
            String[] ids = new Gson().fromJson(text.getValue(), String[].class);
    

Seems like an effective solution. So far, I have not noticed a negative impact on my project.

Note: As stated in the documentation, text is not indexed and cannot be used to query filters and sort order. Therefore, if property SubscriptionIDs need to be indexed, this restriction can cause additional problems.

Related Problems and Solutions