Jello Framework

Jello Entity is the core component which the application model is based on. Jello uses JDO (Java Data Objects) to map and store Jello entities in the database. If you are familiar with JDO or your application is already using JDO, you will find it very easy and intuitive to migrate your app to Jello.

Jello has an improved persistence mapping model over the basic JDO implementation. Its superior model maps entities in different packages to separate name spaces in the database, providing a better way to organize the code and shape your application authorization model.

You define a Jello Entity by extending the JelloEntity class. Adding JDO @PersistenceCapable annotation will allow you to persist the entity in the database. To expose it via RESTfull API, you will need to add the @Accessible annotation.


Entity declaration

1
2
3
4
5
6
7
package app;
					
@Accessible
@PersistenceCapable
public class Person extends JelloEntity {
   ...
}

JelloEntity (jello.model.JelloEntity)

The base class for all Jello persistence entities.


@Accessible (jello.security.Accessible)

Marks the entity as accessible to all via REST requests. The @Accessible annotation can get authorization parameters (for data-access-control options, refer to the Jello Authorization Model).


@PersistenceCapable (javax.jdo.annotations.PersistenceCapable)

Marks the entity as persistence capable. This is the common use case and should be set for all the classes that extend JelloEntity.



@Searchable, @NotSearchable (jello.annotation.Searchable)

Determine whether to add the entity to the search index. By default, Jello will treat all* entities as searchable. To override this behavior, add the following to app.yaml. (See also the application configuration file.)

    servlet: jello.JelloServlet
    name: Jello
    init_params:
      jello.search.enabledByDefault: false					

* For security reasons, an entity which contains instance level access will not be treated as searchable.

In the text search database, the class package name will be mapped to the namespace and the class full name will be mapped to the index name.




Entity Key

The entity key is composed of all fields annotated with @KeyElement. In addition to all fields specified by the user, Jello will add implicit __ID key field to hold the entity key value.

In case no key element is specified, an auto generated UID will be assigned as the entity key.

In case one key element is specified, the entity key value will be the same as the key element value.

1
2
3
// example of entity key:  John Doe
@KeyElement
public String fullName;

In case of multiple key elements:

1
2
3
4
5
// example of entity key:  123456-CA
@KeyElement
public String licensePlate;
@KeyElement
public String registeredAtState;





Field types

Core types: String, Integer, Double, Boolean, Date

Enum type

Reference type

Association type

Calculated type

Attachment type

Owned nested type

Collection type



new field dialog

Field annotations modifiers

  • @Persistent (javax.jdo.annotations.Persistent)
    Marks the field as persistent. The field value will be saved in the database. All entity fields are persistent by default so in most cases this annotation can be omitted.

  • @Expose (jello.annotation.Expose)
    Marks the field as accessible to all via REST requests. This annotation affects only the REST API, while the Java access level is determined, as usual, by the field java access modifiers (public/private). In case of exposure of a private field, the Jello annotation processor will issue a warning, letting you know that this field will be exposed via REST calls regardless of its 'private' modifier. The @Expose annotation can get authorization parameters (for data-access-control options, refer to the Data Access Control section).

  • @Required (jello.annotation.Required)
    Marks the field as required. This annotation affects both REST (Create, Update) operations and the Java API create(), save(), update().

  • @Cardinality (jello.annotation.Cardinality)
    Specifies the field cardinality. This annotation affects both REST (Create, Update) operations and the Java API create(), save(), update().

    This annotation is valid only for multiple values fields (Set or List). Cardinality has priority over @Required and will override it.

    Syntax:
    @Cardinality("number..number|*") // for example: @Cardinality("2..*")

  • @ReadOnly (jello.annotation.ReadOnly)
    Marks the field as read-only by REST API. This annotation affects only the REST (Create, Update) operations while the Java access level is determined, as usual, by the field java access modifiers (public/private, final).

  • @Final (jello.annotation.Final)
    Marks the field as final by REST API. This annotation affects only the REST (Update) operation. It allows one to specify a value for the field when creating the instance. Any attempt to update the field's value after instance creation will fail. The Java field access behavior is determined, as usual, by the field Java modifier (final).

  • @NotPersistent (javax.jdo.annotations.NotPersistent)
    Marks the field as as not persistent. The field value will not saved in the database. This option is typically used for Association fields or Calculated fields.


  • Audit fields

    Jello entities maintain Audit fields for all records. Each entity includes the following audit fields by default:

    @Expose @Audit @ReadOnly
    private Date createdOn;
    	
    @Expose @Audit @ReadOnly
    private User createdBy;
    	
    @Expose @Audit @ReadOnly
    private Date changedOn;
    	
    @Expose @Audit @ReadOnly
    private User changedBy;
    

    Audit fields are not included in the REST response by default. To include Audit fields in the response, use the $audit=true query option (see REST Query Options - $audit). Note: Audit fields will be exposed only if the logged-in user has CREATE permission for the entity. (For data-access-control options, refer to the Data Access Control section.)

  • @Audit (jello.annotation.Audit)
    Marks the field as an Audit field. This field's REST expose behavior will follow the system audit fields.


  • Enum field type

    Any enumeration type can be used as a field type. (The @Lable annotation is optional).
    @Expose public Color background;
    
    public enum Color { @Label("Red") RED, @Label("Green") GREEN, @Label("Blue") BLUE };
    

    The Entity metadata includes the enumeration definition as shown below:

    {
      name: "background",
      type: "app.Box.Color"
    }
    ...
    enums: {
      app.Box.Color: [
        {
          value: "RED",
          label: "Red"
        },
        {
          value: "GREEN",
          label: "Green"
        },
        {
          value: "BLUE",
          label: "Blue"
        }
      ]
    }
    

    Calculated field

    Calculated fields are not saved in the database but rather are calculated on demand whenever an entity's instance is being fetched. From REST call perspective, calculated fields look like any other read only field. You define a calculated field by marking it as @NotPersistent and adding a method with the same name as the field with no parameters. The method must return the same type as the field's type.
    @NotPersistent @Expose
    private String calculatedField;
    public String calculatedField() {
    	return "I am calculated field: " + Math.random();
    }
    

    Collection field

    Both Set and List collections are supported for the following types: Core types, Enum, Reference type, and Managed nested type types.

       @Expose public List<String> messages;
    
       @Expose public Address managedAddress;
       @Expose public List<Color> colorsList;
       @Expose public Set<Color> colorsSet;
       enum Color {RED, GREEN}
       
       @Reference(Product.class)
       @Expose public List<Key> productsList;
       @Expose public Set<Key> productsSet;
       
       @Expose public List<Address> addressesList;
       @Expose public Set<Address> addressesSet;
       
       @PersistenceCapable
       static class Address {
          String street;
          String city;
          String state;
          String zipCode;
       }
    

    UX annotations

    Entity elements can be annotated with UX annotations. You can add any of the jello.ux annotations such as Label, Hint, Control, etc. (see list of all available UX annotation). You can even define custom UX annotations which will be added to the element meta data object (see Define Custom UX Annotations).


    Before and After Save methods

    Overrides the default JelloEntity empty methods. These functions are used for adding custom validation and records manipulation before and after saving the record. It applies to both REST (create, update) API calls and JAVA create(), save(), update() API.

    These methods are handy especially since only the default empty constructor is invoked during REST call.

    @Override
    protected Car beforeSave() throws IllegalRequestResource {
       // Here you can add code that will be executed before saving the record.
       if(something-fishy)
          throw new IllegalRequestResource( "something fishy while trying to save " +  this.getID() );
       return this;
    }
       
    @Override
    protected Car afterSave() {
       // Here you can add code that will be executed after saving the record.
       return this;
    }
    

    Before and After Delete methods

    @Override
    protected Car beforeDelete() throws IllegalRequestResource {
       // Here you can add code that will be executed before deleting the record.
       if(something-fishy)
          throw new IllegalRequestResource( "something fishy while trying to delete " +  this.getID() );
       return this;
    }
       
    @Override
    protected Car afterDelete() {
       // Here you can add code that will be executed after deleting the record.
       return this;
    }
    


    Static Entity

    Static entity serves as a service endpoint that can only expose static actions via REST calls. Any attempt to persist an instance of this entity in the database will fail.

    @Accessible
    public class AppService extends StaticEntity {
       // Static actions only
    }
    

    Last updated April 28, 2016.