husayt husayt - 3 months ago 9
Java Question

Appengine Key serializes transient appIdNamespace

I am creating a

com.google.appengine.api.datastore.Key
in namespace
A
and adding it as a field to
DeferredTask
to run in different namespace
B
. That task is then sent to a Queue and is being executed on a different box.

Because, it is created in namespace A that key has
A
as its original namespace value (in its
appIdNamespace
field).

But as the key's
appIdNamespace
field is transient and
DeferredTask
uses serialization I expect the
appIdNamespace
field to be null on deserialization (and thus to get initialised to have namespace value of
B
) when being run from namespace
B
.

But instead key still has
A
as a value for namespace in its
appIdNamespace
field after deserialization, when task runs in namespace
B
.

I am sure I am missing something here, but can't explain. What am I missing here?

Answer

Yes, I just checked. Serialization process is overridden for Key which serializes the appIdNamespace if it's not null via the appId field which is not transient:

private void writeObject(ObjectOutputStream out) throws IOException {
    if (appIdNamespace != null) {
      appId = appIdNamespace.toEncodedString();
    }
    out.defaultWriteObject();
}

And readObject() properly decodes the appIdNamespace from the deserialized appId field:

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    if (appId != null) {
        appIdNamespace = AppIdNamespace.parseEncodedAppIdNamespace(appId);
        appId = null;
    } else {
        appIdNamespace = new AppIdNamespace(DatastoreApiHelper.getCurrentAppId(), "");
    }
    validateAppIdNamespace(parentKey, appIdNamespace);
}

Source: Key.java