Skip to content

UpgradeVersion5ToVersion6

centoria edited this page Aug 10, 2020 · 10 revisions

Upgrading Objectify v5 to v6

Objectify v6 attempts to preserve as much of the public API surface of v5 as possible, but uses a whole new Google-provided SDK to access the datastore. In cases where Objectify's API exposes SDK classes, or the new SDK has differing behavior, changes in your application may be required. These are catalogued below.

  • You will need to call ObjectifyService.init(), possibly passing in a custom ObjectifyFactory instance. The previous behavior of starting out with a default ObjectifyFactory incurs a connection cost and may fail in environments which require a custom DatastoreService.

  • The default ObjectifyFactory uses the default environment credentials (ie, DatastoreOptions.getDefaultInstance().getService(). If you need to construct a special Datastore, you can pass this in to the ObjectifyFactory constructor. Call ObjectifyService.init(new ObjectifyFactory(mydatastore)).

  • There's no longer an automatically provisioned memcache service. Objectify's memcache integration relies on the Spymemcached library to talk to a plain old memcached server running on a port/IP address. The default ObjectifyFactory constructor disables memcache (for now); pass in an explicit MemcachedClient to enable caching.

  • The Cloud SDK generates a new format for stringified keys (key.toUrlSafe()), which is something to be aware of if you store these keys in other databases (or user-bookmarked urls). To help, Objectify accepts either form when constructing keys with Key.create(String). To generate one form or the other, call one of:

    • key.toUrlSafe(), which looks like partition_id+%7B%0A++project_id%3A+%22test-project%22%0A%7D%0Apath+%7B%0A++kind%3A+%22Thing%22%0A++id%3A+123%0A%7D%0A
    • key.toLegacyUrlSafe(), which looks like ag1zfnZvb2Rvb2R5bmUwcgcLEgFCGAEM
  • The memcached serialization format for Objectify v5 and v6 differ. You can run v5 and v6 in parallel against the same datastore, but not the same memcached. Not that you could anyways; there is not currently a Cloud SDK interface to the memcached service!

  • Java serialization of Objectify's Key<?> and Ref<?> classes is not compatible between v5 and v6. If you @Serialize structures that contain fields of these types, you will have problems. Objectify's Key<?> is just a wrapper for the SDK's Key, and that is now a totally different class.

  • ObjectifyFactory.allocateIdRange() has been removed. There is no longer an explicit range-allocation function in the SDK. You can still allocate ids (and blocks of ids) using allocateId() and allocateIds().

  • ofy().transactionless().load... has been changed. Now its ofy().transactionless(() -> ofy().load()...).

  • ofy().consistency(Consistency.EVENTUAL).load()... uses an SDK enum that no longer exists. The new code is ofy().load().option(ReadOption.eventualConsistency())....

  • ofy().deadline(blah) has been removed. The new SDK does not offer this ability; if you want to change connection behavior, use the SDK DatastoreOptions to construct a special Datastore and pass it to the ObjectifyFactory.

  • NOT and IN filters are not supported by the new SDK. You will get a runtime error if you try to ofy().load().type(Thing.class).filter("field !=", value) or filter("field IN" values).

  • The new SDK uses a new set of classes to manage query cursors, and Objectify has always exposed these directly. If you use cursors, you will have to change your code:

    • com.google.appengine.api.datastore.Cursor is now com.google.cloud.datastore.Cursor
    • com.google.appengine.api.datastore.QueryResultIterator is now com.google.cloud.datastore.QueryResults
    • com.google.appengine.api.datastore.QueryResultIterable is now com.googlecode.objectify.cmd.QueryResultIterable (an Objectify-provided interface since there is no analogue in the SDK)
  • If you use composite filters, the new SDK has a new set of Filter classes.

  • There is no more Query.reverse() method, as this is no longer supported by the underlying SDK.

  • The underlying SDK does not have a query count() operation. Objectify simulates this by issuing a keys-only query and counting the keys. This might perform differently from the old SDK; then again, the old SDK was probably just doing this behind the scenes (only Google knows for sure).

  • The old SDK did not save empty lists (it just ignored them). The new SDK does save empty lists. This doesn't matter a whole lot when working with POJOs but if you are using Objectify and the low-level APIs simultaneously you may notice the difference.

  • The new SDK has a quirk when saving list properties. If some values are indexed and others aren't, the indexed ones get reordered to the front of the list. To work around this behavior, whenever Objectify detects a heterogenously-indexed list, it forces everything in the list to be indexed.

  • Blobs can be indexed in the new SDK. In the old SDK, instructions to index a Blob were simply ignored; in the new SDK, the instruction is respected - but you'll get an error if you exceed 1500 bytes. Note that this applies to @Serialize fields as well.

  • In embedded maps, you cannot use keys containing dots, those have special meaning in the new API. If you must have dots in your keys, you can use an @Stringify Stringifier to escape them

  • Nearly every internal API in Objectify has changed in some way, including the Translator APIs. If it isn't obvious what you need to do, ask on the Objectify google group.