Skip to content

Latest commit

 

History

History
164 lines (133 loc) · 6.3 KB

File metadata and controls

164 lines (133 loc) · 6.3 KB

  1. summary API design for Objectify 4.0

Table of Contents

What's wrong with the old API?

  * Putting Key<?> in the data model is a PITA sometimes
    * Hard to create tidy data models for jsonification or serialization to clients; tends to require ugly @Transient fields
    * Manually populating @Transient fields is errorprone and can be inefficient
  * Asynchrony shoehorned in
    * Most operations already have interfaces that can hide asynchrony, for example:
      * {{{Map<Key<Thing>, Thing> map = ofy.get(k1, k2)}}} can be async
      * {{{Result<Map<Key<Thing>, Thing>> map = ofy.async().get(k1, k2)}}} is unnecessary
  * As get() methods for refs and unfetched entities added, API on Objectify is exploding
  * Reliance on JPA annotations is problem for some
  * Defaulting fields to indexed was a bad idea

Design goals

  * Make Key<?> optional in the data model
  * Automatic fetching of object graphs
    * Fine tuning with easy-to-use fetch groups (not JDO fetch groups!)
  * Use interfaces to hide asynchrony from client
    * *Everything* should be asynchronous!
  * Use Result<?> when asynchrony cannot be hidden (ie, returning concrete classes)
  * Consistent interface for batch get vs filtering
  * All core config/command objects are immutable
  * Fix poor initial design decisions

Cleanup

  * Stop using JPA annotations
  * Convert all annotations to imperative form (eg @Index instead of @Indexed)
  * All fields default to not indexed
  * Session cache enabled by default
  * Eliminate ObjectifyOpts, provide a fluent way to define options
  * More control of Objectify instance; switch read consistency, disable/enable caches, etc
    * Objectify instance remains immutable, however
      * Well not exactly, because the session cache is shared among an instance chain

Annotation changes

All annotations live in com.googlecode.objectify.annotation. JPA annotations are not used at all.

|| Old || New || Notes || || @Entity || @Entity || unchanged || || @Indexed || @Index || || || @Unindexed || @Unindex || || || @Transient || @Ignore || || || @NotSaved || @IgnoreSave || || || || @IgnoreLoad || Needed because @AlsoLoad doesn't "steal" anymore || || @PostLoad || @OnLoad || || || @PrePersist || @OnSave || || || @Cached || @Cache || || || @Embedded || @Embed || || || @Serialized || @Serialize || || || || @Load || previously proposed as @Fetch || || || @OnLoadDelegate || see below || || || @OnSaveDelegate || see below ||

New annotations which can be put at Class level:

  * @OnSaveDelegate(SomeClass.class)
  * @OnLoadDelegate(SomeClass.class)

In this case, SomeClass implements standard interfaces, something like:

Since all such objects are created with the overridable method ObjectFactory.create(), it's easy to pull these from Guice.

Note: lifecycle delegates have not been implemented yet.

Example of class with fetching

The Ref class

API examples