About Garfa

Garfa - is Groovy ActiveRecord for Google Appengine

It's a tiny wrapper around Objectify 4, and should work with any Groovy project on Appengine. It's pretty safe to use Garfa in your project, because all underlying work is done by Objectify, and if you have something very specific you could always dig down to raw Objectify.

Garfa extends your database models with methods for querying, storing and updating models for Google Appengine Datastore.


Maven dependency




Project is licensed under Apache 2 license.

How To Use


You need to register classes through Garfa on app start.

ObjectifyFactory objectifyFactory = //... you need to have Objectify already configured there
Garfa garfa = new Garfa(objectifyFactory)

// Car and Dealer is our models
List<Class> models = [Car, Dealer]

// add magic to our models 

Init as a Spring Framework bean

If you have a Spring Framework app, you could easily initialize Objectify and Garfa with your @Configuration class, like:

class StorageConfig {

    ObjectifyFactory getObjectifyFactory() {
        ObjectifyFactory objectifyFactory = new ObjectifyFactory()
        Garfa garfa = new Garfa(objectifyFactory)
        def models = [
        models.each { Class clz ->
            objectifyFactory.register(clz) // register with Objectify
            garfa.register(clz) // register with Garfa
        return objectifyFactory


Basic Samples


class CarModel {

    Long id

    String vendor
    String model
    int year

    void beforeInsert() {
        if year == 0 {
            year = 1896


class Car {

    Long id
    Key<CarModel> model

    int price
    String color

Create entities

CarModel mustang = new CarModel(vendor: 'Ford', model: 'Mustang', year: 2012) true) //sync save
Car redMustang = new Car(model: mustang.key, price: 22000, color: 'red') //async save


Current instance of entity have .update method, that accept a Closure that will update db. Notice, that this method will load a fresh version from DB, and try to update. Also it will try to perform this operation up to 3 times if fail (for the situation when you're updating same entity from different threads)

Ok, lets make a discount!!! $22000 -> $21000:

Car withDiscount = redMustang.update {
  price = 21000

.update method also return updated instance. Or throw exception if failed to update (only when all 3 tries are failed).


Car blackMustang = Car.findFirstByModelAndColor(mustang.key, 'black')

// load model with ID 5161
CarModel foo = CarModel.load(5161)

List<Car> allYellow = Car.findAllByColor('yellow')

Model, Color, etc is a entity fields to filter.


Get item by ID

There is two method for loading data from database:

Model.get(id or key)

Will throw error if there is no entity with specified ID

Long id = 1
try {
  Car car = Car.get(id)
} catch (NotFoundException e) {

Key<Car> carKey = new Key<Car>(Car, 1)
try {
  Car car2 = Car.get(carKey)
} catch (NotFoundException e) {

Model.load(id or key)

Will returns null if there are no entity with specified ID.

Long id = 1
Car car = Car.load(id)
if (car == null) {
   ... not found

Key<Car> carKey = new Key<Car>(Car, 1)
Car car2 = Car.load(carKey)
if (car2 == null) {
   ... not found

Model.getAll(list of ids or keys)

Loads list of entities for specified ids:

List<Car> cars = Car.getAll([1, 2, 3])

Get a Query for a Model

You could get a Objectify Query for a model:

Query<Model> query = Model.queryWhere([<fields>], [<params>])


  • fields - list of field filters, where keys is or simple field names (that mean equality filter), or string as fieldname + operator. Like: [model: 'Ford'] or ['model =': 'Ford'] or ['count >': 5].
  • optional query parameters - like [limit: 4] or [order: '-count']

Find Where

There is an another method for querying:

Clazz.findWhere([<fields>], [<params>]) {
  // code executed against Query


  • fields - list of field filters, where keys is or simple field names (that mean equality filter), or string as fieldname + operator. Like: [model: 'Ford'] or ['model =': 'Ford'] or ['count >': 5]. First two are equal filters
  • optional query parameters - like [limit: 4] or [order: '-count']
  • closure - more flexibility when you need something specific. It's your code block that will be executed against prepared Query. Like Car.findWhere([], []) { limit(5) } (btw, it's the same as .findWhere([], [limit: 5]))

Possible query parameters: * limit * offset * ancestor - key or parent entity * order - in format [order: 'model'] standard ascending order, or [order: '-year'] for descending order * cursor - web-safe string for cursor, or instance

For example:

//get maximum 20 cars where count > 10, ordered by count field, descending
List cars = Car.findWhere(['count >': 10], [order: '-count', limit: 20])

Find by Ancestor

//a parent instance
CarModel fordFocus

//find by parent:
List<Car> cars = Car.findByAncestor(fordFocus)

//or by a parent key:
List<Car> cars = Car.findByAncestor(fordFocus.key)

Save and Update

Create a new data object

Use .save() method

car = new Car(
    brand: 'Ford',
    model: 'Mustang',
    count: 0

Update item in transaction

GAE uses optimistic-locking transactions, so, to update an item, Garfa tries to load fresh instance from DB and execute your code against this instance.

If save of update instance is failed, Garfa retries this steps again, at least 3 times.


car.update { Car loaded ->

Model.update(id, Closure)

Car.update idOrKey, { Car loaded ->


  • car - current instance
  • idOrKey - id or Key of instance to update
  • loaded - instance loaded for update


Just use .delete() method:

Car car = Car.get(15)

Dynamic Finders

Garfa supports dynamic finders like:

Car.findByModelAndYear("Mustang", 2008)

Model.findBy*(...), Model.findBy*(..., options)

Return list of entries, filtered by specified fields

Options is a optional argument, it's a Map with following possible entries:

  • limit - max number of elements, like [limit: 2]
  • offset - initial offset, like [offset: 10]
  • sort - sort by field value. Value of this option is a field name to use sort for sorting. By default it sorts in ascending order, to use descending use - as a prefix to field name. Like [sort: 'model], [sort: '-year']
  • cursor - string value or Cursor instance to use for this query

Model.findFirstBy*(...), Model.findFirstBy(..., options)

Same as findBy, but returns first element only. Or null if not found.


Car car1 = Car.findFirstByVendor('Vaz')
Car cheapFord = Car.findFirstByVendor('Ford', [sort: 'price'])

List<Car> allFords = Car.findByVendor('Ford')
List<Car> firstPageFords = Car.findByVendor('Ford', [limit: 10])

Down to Objectify


You have direct access to Objectify's Query, by using two following methods:

  • .findFirst {}
  • .findAll {}

where you can pass the code that can modify any options of passed Query object. Please notice, that query instance, it's no a passed parameter, your code will operates directly against query instance, as an DSL.

For example:

Car.findAll {
  filter('vendor =', 'Ford')

More Objectify

Use method .withObjectify {} of a model, this Closure will be called agains Objectify instance, so you can do whatever you want:

Key key = ....
boolean loaded = CarModel.withObjectify {
  //all methods here are delegated directly to Objectify instance





Called on both insert and update

class Car {
  void beforeSave() {


Called before first save (when Id is null)

class Car {
  void beforeInsert() {


Called before object update

class Car {
  void beforeUpdate() {


Project Links

Used technologies