Written for AI agents. Human? Read the human version →
jfaster.ai / docsView raw Markdown

JFaster User Guide

1. Introduction

JFaster is a code generator that, from a single .txt file, generates all the files (.html, .java, .hbm.xml, SQL) that compose a web application.

Applications are defined in a text file containing ENTITIES (defined with lines starting with an uppercase letter) which in turn have PROPERTIES (lines starting with a lowercase letter, preceded by a tab). Entities can also have: subsets, listings, filters, actions, and defaultsets.

For example, if we want an app with PEOPLE who work at COMPANIES, we write:

Person menu="CRM"
   name r d                                      // required field with 'display'
   lastName r d
   age integer                                   // integer field
   company Company subset="active"               // relationship to Company entity. The HTML form will show a <select> with an <option> for each record in the "active" subset
   addresses ei x set childproperty="person"    // Master/detail pattern: a person has many addresses
   emails set                                    // 'emails' is a multi-valued field
                                                 // In Java: Set<String>
                                                 // In SQL: table person_emails(person BIGINT(20) references person(id), emails VARCHAR(255))

Company menu="CRM"
   name r d
   active boolean default="false"               // boolean field. In Java: boolean. In HTML form: <input type="checkbox">
   headCount integer ds formula="(SELECT COUNT(*) FROM person WHERE person.company = id)"
                                                // The "formula" attribute maps to Hibernate's "formula" attribute in Company.hbm.xml

   <subset name="active">
      <condition field="active" value="true" />
   </subset>

Address
   person Person fixed                          // fixed field, cannot be edited. HTML form shows data in a <span>
   street
   number integer
   country Country                              // HTML form shows a <select> with all countries
   province Province subset="forCountry" subsetparams="country"
                                                // HTML form shows a <select> for provinces that updates its <option>s based on the selected country
   city autosuggest

Country menu="Places"
   name d r

Province menu="Places"
   <subset name="forCountry">
      <param name="country" entity="Country" />
      <condition field="country" value="country" />
   </subset>
   name d r
   country Country r

SendEmail transient="transient" menu="Actions"  // Entities marked "transient" are not saved to database. They should have verb names (like "Send")
   person Person fixed
   subject
   body text

Another Example

Person @Person

   <filter name="name" property="name" display="primary" />

   <defaultset name="newForCompany">
      <param name="company" entity="Company" />
      <default name="company" value="company" />
      <default name="country" value="company.country" />
   </defaultset>

   <subset name="forCompany">
      <param name="company" entity="Company" />
      <condition field="company" value="company" />
   </subset>

   <listing name="forCompany" />

   <action name="sendEmail" label="Send Email" location="local" widget="button" type="relatedentity" entity="SendEmail" defaultset="forPerson" />

   #tab label="Personal Data"

      name d style="font-size:20px;font-weight:bold;" maxlength="20" minlength="5"
      lastName d "Last Name" style="font-size:20px;font-weight:bold;"
      age integer fixed transient class="ageClass"
      ageGroup integer expr="(this.age / 10)*10"
      height integer hidden
      color invisible
      birthdate date ds
      comments text
      address text disabledif="isCompanyActive = 'true'" \
         <action name="viewAddress" type="javascript" function="viewAddress" label="View address" />
      company Company \
         <action name="viewCompany" type="openentity" label="View" />
      country Country
      province Province subset="forCountry" subsetparams="country"
      city City subset="forProvince" subsetparams="province"
      email
      phones sortedset sort="com.example.utils.PhoneComparator" \
         <displaycondition expr="company.active == true">
            <param name="company" entity="Company" value="company" />
         </displaycondition>
      isCompanyActive boolean widget="select" \
         <dynamicvalue expr="company.active">
            <param name="company" entity="Company" value="company" />
         </dynamicvalue>
      languages set Language widget="checkbox" displayif="isCompanyActive = 'true'"
      skills set enum enumset="Skills"
      weight double tooltip="Weight is in kg."
      cv text

   #tab label="Sent Emails"

      <embeddedlisting name="sentEmails" entity="Email" subset="forPerson" subsetparams="." />

Company @Companies defaultlisting="main"

   <listing name="main">
      <tab name="all" label="All" />
      <tab name="active" label="Active" subset="active" />
   </listing>

   <subset name="active">
      <condition field="active" value="true" />
   </subset>

   <filter name="name" property="name" display="primary" />
   <filter name="category" property="category" display="primary" />

   <action name="viewWebsite" label="View Website" location="local" widget="button" type="javascript" function="viewWebsite" />
   <action name="newPerson" label="New Person" location="local" widget="button" type="relatedentity" entity="Person" defaultset="newForCompany" />
   <action name="deactivate" label="Deactivate" location="listing" widget="button" type="relatedentity" entity="DeactivateCompanies" defaultset="forCompanies" />

   name d
   active boolean default="true"
   address text
   country Country ds displayif="name = 'Apple'"
   province Province subset="forCountry" subsetparams="country" displayif="active = 'true'"
   city City subset="forProvince" subsetparams="province" displayif="active = 'true'"
   neighborhood autosuggest="autosuggest"
   category Category displayif="active = 'true'"
   headCount integer ds formula="(SELECT COUNT(*) FROM person WHERE person.company = id)"

   <embeddedlisting name="persons" entity="Person" subset="forCompany" subsetparams="." listing="forCompany" defaultset="newForCompany" defaultsetparams="." />

Category @Companies
   name d

Country @Configuration
   name d

Province @Configuration
   <subset name="forCountry">
      <param name="country" entity="Country" />
      <condition field="country" value="country" />
   </subset>

   country Country ds
   name d

City @Configuration
   <subset name="forProvince">
      <param name="province" entity="Province" />
      <condition field="province" value="province" />
   </subset>

   country Country
   province Province subset="forCountry" subsetparams="country"
   name d

DeactivateCompanies @ transient="transient"
   <defaultset name="forCompanies">
      <param name="companies" entity="Company" collection="set" />
      <default name="companies" value="companies" />
   </defaultset>

   <html>Warning! These companies will be deactivated</html>
   companies set Company fixed

SendEmail @Actions transient="transient" stereotype="Async"
   <defaultset name="forPerson">
      <param name="person" entity="Person" />
      <default name="recipient" value="person.email" />
      <default name="person" value="person" />
   </defaultset>

   person fixed Person
   recipient
   subject
   body text

Language @Languages
   <next type="function" function="alert" />

   name d

Email @Emails noadd="noadd" noremove="noremove"
   <subset name="forPerson">
      <param name="person" entity="Person" />
      <condition field="person" value="person" />
   </subset>

   person Person fixed ds
   datetime fixed ds
   recipient fixed ds
   subject fixed ds
   body text fixed ds

Product @Products

   #tab Main
      title d
      price double ds style="font-size: 20px; color: red;"
      <embeddedlisting name="invoices" entity="Invoice" subset="forProduct" subsetparams="." />

      attributes ProductAttribute set ei x childproperty="product"

   #tab Prices

      <embeddedlisting name="changes" entity="PriceChange" subset="forProduct" subsetparams="." />

ProductAttribute @
   product Product
   name
   value

PriceChange @History noadd="noadd" noremove="noremove"
   <subset name="forProduct">
      <param name="product" entity="Product" />
      <condition field="product" value="product" />
   </subset>

   product Product ds fixed
   datetime ds fixed
   price double fixed ds

Invoice @Invoices

   <next type="function" function="nextInvoice" />

   <subset name="forProduct">
      <param name="product" entity="Product" />
      <restriction expr="EXISTS (FROM InvoiceLine il WHERE il.invoice = me AND il.product = ?)">
         <param value="product" />
      </restriction>
   </subset>

   invoiceDate date fixed default="now"
   person Person d \
      <action name="edit" type="openentity" label="Edit" />

   invoiceLines InvoiceLine sortedset ei x childproperty="invoice" sortexpr="obj.quantity"

InvoiceLine @Invoices
   invoice Invoice
   quantity integer ds
   product Product ds
   <property name="price" type="double" label="Price" display="secondary">
      <dynamicvalue expr="productParam.price">
         <param name="productParam" entity="Product" value="product" />
      </dynamicvalue>
   </property>
   <property name="total" type="double" label="Total" display="secondary">
      <dynamicvalue expr="productParam.price * quantity">
         <param name="productParam" entity="Product" value="product" />
         <param name="quantity" type="integer" value="quantity" />
      </dynamicvalue>
   </property>
   totalCalculated double calculated="price * quantity"

2. Generated Application

2.1. Files Generated for Each Entity

For each entity, JFaster generates several files.

For example, for the entity "Person", it generates:

FileDescription
src/main/webapp/Main/Person_form.htmlA form with <input> or <select> elements for data entry/editing. The form loads dynamically with data from the REST API GET /xml/Person/[0-9]+
src/main/webapp/Main/Person_list.htmlA listing with <table> and a <tr> for each record. The listing loads dynamically with data from the REST API GET /xml/Person
src/main/java/com/my/package/entities/Person.javaEntity class with all fields, getters, and setters
src/main/java/com/my/package/services/PersonServices.javaService class with methods Person find(String id), Collection<Person> findPage(), and Long store(String id, Person obj)
src/main/java/com/my/package/dao/PersonDAO.javaDAO interface
src/main/java/com/my/package/dao/hibernate/HibernatePersonDAO.javaHibernate DAO implementation
src/main/resources/com/my/package/dao/hibernate/Person.hbm.xmlHibernate mapping file

2.2. Generated REST API

For each entity, REST services are generated. For example, for the entity Person:

EndpointMethodDescription
GET /xml/PersonPersonServices.findPage()Returns paginated list of all persons
GET /xml/Person/[id]PersonServices.find()Returns a single person by ID
POST /xml/Person/[id]PersonServices.store()Creates or updates a person

Additionally, for each subset, a service is generated:

EndpointDescription
GET /xml/Person/SUBSET_NAME/[OPTIONAL_PARAMS]Exposes PersonServices.findSubsetSUBSET_NAME()

3. Entities

3.1. Persistent vs Transient Entities

Unless an entity is marked as transient, a corresponding table is created in the database for each entity.

This concept is inherited from EJB 2: persistent entities are analogous to Entity Beans, while transient entities are analogous to Session Beans.

Naming conventions:

Example of a transient entity:

SendEmail transient="transient" menu="Actions"
   person Person fixed
   subject
   body text

Transient entities are useful for:

3.2. Entity Attributes

AttributeDescription
menu="MenuName"Places the entity in a specific menu group
@MenuNameShorthand for menu="MenuName"
transient="transient"Entity is not persisted to database
order="field desc"Default ordering for listings
defaultlisting="name"Specifies which listing to use by default
noadd="noadd"Disables adding new records
noremove="noremove"Disables removing records
stereotype="Async"Marks entity for asynchronous processing

4. Properties

4.1. Types and Entity Relationships

Each property can specify a type (defaults to string if not specified).

Available types (with Java and SQL mappings):

TypeJavaSQL
integerintINT
longlongBIGINT
doubledoubleDOUBLE
floatfloatFLOAT
booleanbooleanBIT(1)
dateGregorianCalendarDATE
datetimeGregorianCalendarDATETIME
stringStringVARCHAR(255)
textStringTEXT
longtextStringLONGTEXT
fileStringVARCHAR(255)
imageStringVARCHAR(255)

Note: Don't specify type="string" for string properties since it's the default.

Entity relationships are indicated by specifying the entity name after the property name:

Person
   ... name, lastName, other properties ...
   country Country

Country
   name

This creates a foreign key relationship where a Person references a Country.

4.2. Multi-valued Fields

Multi-valued fields allow assigning multiple values to a single field.

Collection types:

TypeJava MappingDescription
setSet / HashSetUnordered, unique values
sortedsetSortedSet / TreeSetSorted, unique values
listList / ArrayListOrdered, allows duplicates

Additional attributes:

Example with multi-valued properties:

Person
   name d r
   emails set
   countries Country set

Country
   name

Generated Java code in Person.java:

private Set<String> emails;
private Set<Country> countries;

Generated SQL tables:

4.3. Master/Detail Pattern

The combination of attributes ei x set implements the master/detail pattern: a common design where a primary entity (master) has a one-to-many relationship with a secondary entity (detail). This pattern is typical in cases like invoices and invoice lines, people and addresses, orders and products.

AttributeMeaningDescription
eiembedded="inline"The secondary entity is displayed within the master's form
xextendable="extendable"New rows can be added (some cases may want fixed rows)
setCollection typeSpecifies the relationship is one-to-many
childproperty="field"Back-referenceThe field in the child entity that references the parent

Example:

Invoice @Invoices
   invoiceDate date fixed default="now"
   customer Customer d
   lines InvoiceLine set ei x childproperty="invoice"

InvoiceLine @
   invoice Invoice
   product Product
   quantity integer
   price double

Additional options:

AttributeDescription
listUse instead of set when order matters
listindex="field"Field that stores the list position
sortexpr="expression"Expression to sort items

4.4. ei x set vs <embeddedlisting>

Both approaches create similar database structures, but they differ in the front-end presentation:

Featureei x set<embeddedlisting>
DisplayEmbedded form with inline editingListing table within the form
Best forSmall number of detail recordsLarge number of detail records
EditingDirect inline editingOpens separate form for each record
Adding recordsInline with x (extendable)Via "Add" button in listing
Use caseInvoice lines, addressesOrder history, sent emails

Example with <embeddedlisting>:

Person
   <subset name="forCompany">
      <param name="company" entity="Company" />
      <condition field="company" value="company" />
   </subset>

   name d r
   lastName d r
   company Company

Company
   name d r
   <embeddedlisting name="employees" entity="Person" subset="forCompany" subsetparams="." />

4.5. Property Behavior

Properties can have the following behavior attributes:

AttributeShorthandDescription
required="required"rField is mandatory
display="primary"dField is shown in listings and as entity description
display="secondary"dsField is shown in listings but not as primary description
hidden="hidden"hiddenField is not shown in forms
invisible="invisible"invisibleField is completely hidden (not even in HTML)
disabled="disabled"disabledField is shown but cannot be edited
fixed="fixed"fixedField is displayed as read-only text (not an input)
readonly="readonly"readonlyInput is read-only
transient="transient"transientField is not persisted to database

Conditional behavior:

AttributeDescription
displayif="field = 'value'"Show field only when condition is true
visibleif="field = 'value'"Control visibility based on condition
disabledif="field = 'value'"Disable field based on condition

Example:

Person
   hasAddress boolean
   street displayif="hasAddress = 'true'"
   number integer displayif="hasAddress = 'true'"
   apartment displayif="hasAddress = 'true'"

4.6. Property Labels and Styling

AttributeDescriptionExample
"Label"Custom label (after property name)firstName "First Name"
style="..."Inline CSS stylesstyle="width:300px;"
class="..."CSS classclass="highlighted"
maxlength="n"Maximum input lengthmaxlength="100"
minlength="n"Minimum input lengthminlength="5"
tooltip="text"Hover tooltiptooltip="Enter weight in kg"
widget="type"Custom widgetwidget="jdatepicker"

4.7. Advanced Property Features

FeatureDescription
formula="SQL"Hibernate formula for calculated fields
expr="expression"Client-side calculated expression
calculated="expression"Server-side calculated field
default="value"Default value for new records
autosuggestEnables autocomplete suggestions
<dynamicvalue>Dynamically computed value based on other fields

Example with <dynamicvalue>:

InvoiceLine @
   product Product
   quantity integer
   <property name="total" type="double" label="Total">
      <dynamicvalue expr="product.price * quantity">
         <param name="product" entity="Product" value="product" />
         <param name="quantity" type="integer" value="quantity" />
      </dynamicvalue>
   </property>

5. Subsets

5.1. Definition

A subset is a filtered collection of records from an entity. For example, if we have a Student entity with an active field, we can have an "activeStudents" subset containing only active students.

Basic subset declaration:

Student
   <subset name="active">
      <condition field="active" value="true" />
   </subset>

   name d r
   active boolean

For each subset, you define which conditions a record must meet to be included. Conditions are defined using <condition>, <restriction>, <and>, and <or> tags.

5.2. Using Subsets

Once declared, a subset can be used in:

1. Properties - To limit selectable values:

Enrollment
   student Student subset="active"

2. Listings and tabs:

Student
   <listing name="main">
      <tab name="all" label="All" />
      <tab name="active" label="Active" subset="active" />
   </listing>

3. Embedded listings:

Company
   <embeddedlisting name="employees" entity="Person" subset="forCompany" subsetparams="." />

5.3. Parameterized Subsets

Subsets can receive parameters to filter dynamically. Parameters are declared with <param> and used in conditions.

Example - Provinces filtered by country:

Province @Configuration
   <subset name="forCountry">
      <param name="country" entity="Country" />
      <condition field="country" value="country" />
   </subset>

   name d r
   country Country

Country @Configuration
   name d r

Using the parameterized subset:

Address
   country Country
   province Province subset="forCountry" subsetparams="country"

The subsetparams attribute specifies which field(s) provide the parameter values. When the user selects a country, the province dropdown automatically updates to show only provinces for that country.

Multiple parameters:

City @Configuration
   <subset name="forProvinceAndType">
      <param name="province" entity="Province" />
      <param name="type" entity="CityType" />
      <condition field="province" value="province" />
      <condition field="type" value="type" />
   </subset>

Using . as parameter:

When subsetparams=".", the current entity instance is passed as the parameter:

Company
   <embeddedlisting name="employees" entity="Person" subset="forCompany" subsetparams="." />

5.4. Subset Configuration Options

AttributeDescriptionExample
order="field [asc|desc]"Sort order for resultsorder="name asc"
displayproperties="a,b,c"Properties to show in dropdownsdisplayproperties="name,code"
displayset="name"Alternative display configurationdisplayset="simpleDisplay"

Example with ordering:

Lead @CRM
   <subset name="recent" order="createdDate desc">
      <condition field="createdDate" ge="DateUtil.addDays(now(), -30)" />
   </subset>

6. Filters

JFaster allows adding filters to entity listings using the <filter> tag.

6.1. Basic Filters

Attributes:

AttributeDescription
nameInternal filter name (convention: same as property)
propertyThe entity property to filter on
labelDisplay label for the filter
displayLocation: "primary" (visible) or "secondary" (advanced filters)
typeData type for filter input
widgetCustom widget (e.g., "jdatepicker" for dates)

Example:

Person
   <filter name="name" property="name" label="Name" display="primary" />
   <filter name="birthdate" property="birthdate" type="date" display="secondary" widget="jdatepicker" />

   name d
   lastName d
   birthdate date
   email

6.2. Filters with Conditions

For more complex filtering logic, add conditions inside the filter:

LIKE filter (partial matching):

Person
   <filter name="name" label="Name" display="primary">
      <condition field="name" like="concat('%', concat(name, '%'))" />
   </filter>

Date range filters:

Invoice
   <filter name="dateFrom" type="date" display="primary" label="From Date" widget="jdatepicker">
      <condition field="invoiceDate" ge="dateFrom" />
   </filter>
   <filter name="dateTo" type="date" display="primary" label="To Date" widget="jdatepicker">
      <condition field="invoiceDate" le="dateTo" />
   </filter>

Entity filter:

Lead
   <filter name="category" property="category" entity="LeadCategory" display="primary" />

6.3. Filters with Restrictions

Use <restriction> for complex SQL-based filtering:

Lead
   <filter name="template" entity="LeadTemplate" label="Template" display="primary">
      <restriction expr="EXISTS (FROM LeadEvent le WHERE le.leadTemplate = ? AND le.lead = me)">
         <param value="template" />
      </restriction>
   </filter>

6.4. Filters with Multiple Conditions

Using <or>:

Lead
   <filter name="withoutCodes" display="primary" label="Without Code">
      <or>
         <condition field="codes" isnull="isnull" />
         <restriction expr="codes NOT LIKE concat('%',?,'%')">
            <param value="withoutCodes" />
         </restriction>
      </or>
   </filter>

Enum-based filter with multiple options:

Lead
   <filter name="filters" label="Filters" type="enum" enumset="LeadFilters" display="primary">
      <or>
         <restriction expr="(whatsapp IS NOT NULL AND ? = 'withWhatsapp')"><param value="filters" /></restriction>
         <restriction expr="(whatsapp IS NULL AND ? = 'withoutWhatsapp')"><param value="filters" /></restriction>
         <restriction expr="(instagram IS NOT NULL AND ? = 'withInstagram')"><param value="filters" /></restriction>
      </or>
   </filter>

6.5. Filter with flag Attribute

The flag attribute provides shortcuts for common filter operations:

Lead
   <filter name="codes" property="codes" label="Has Code" display="primary" flag="contains" />

7. Listings

Listings define how entities are displayed in list views, including tabs, filters, and available actions.

7.1. Basic Listing

Company @Companies defaultlisting="main"

   <listing name="main">
      <tab name="all" label="All" />
      <tab name="active" label="Active" subset="active" />
      <tab name="inactive" label="Inactive" subset="inactive" />
   </listing>

7.2. Listing Attributes

AttributeDescription
nameListing identifier
noadd="noadd"Hides the "Add" button
noremove="noremove"Hides the "Remove" button
layout="simple"Uses simplified layout
displayfilters="a,b,c"Which filters to show
displayactions="a,b,c"Which actions to show

7.3. Tab Configuration

Each tab can have:

AttributeDescription
nameTab identifier
labelDisplay text
subsetSubset to filter records
displayactionsActions available in this tab

Example with per-tab actions:

Ticket @ noadd="noadd" noremove="noremove"
   <listing name="main">
      <tab name="open" label="Open" subset="open" displayactions="close,reassign" />
      <tab name="closed" label="Closed" subset="closed" displayactions="reopen" />
   </listing>

7.4. Display Properties

Each entity should specify which property is the main description shown in listings and dropdowns using display="primary" (or shorthand d).

Country
   name display="primary"
   capital
   population integer
   president

Or using shorthand:

Country
   name d
   capital
   population integer
   president

Use display="secondary" (or ds) to include additional fields in listings without making them part of the entity description.

7.5. Multiple Listings

An entity can have multiple listings for different contexts:

Ticket @
   <listing name="user" noadd="noadd">
      <tab name="myTickets" label="My Tickets" subset="forCurrentUser" />
   </listing>

   <listing name="admin">
      <tab name="all" label="All" />
      <tab name="unassigned" label="Unassigned" subset="unassigned" />
   </listing>

8. Embedded Listings

An embedded listing displays a related entity's listing within another entity's form.

8.1. Basic Usage

Example - Show employees within a company form:

Person
   <subset name="forCompany">
      <param name="company" entity="Company" />
      <condition field="company" value="company" />
   </subset>

   name d r
   lastName d r
   company Company

Company
   name d r
   <embeddedlisting name="employees" entity="Person" subset="forCompany" subsetparams="." />

8.2. Embedded Listing Attributes

AttributeDescription
nameIdentifier for the embedded listing
entityThe entity to display
subsetSubset to filter records
subsetparamsParameters to pass to the subset (. = current entity)
listingWhich listing configuration to use
defaultsetDefaultset for new records
defaultsetparamsParameters for the defaultset

Complete example:

Company
   <embeddedlisting
      name="employees"
      entity="Person"
      subset="forCompany"
      subsetparams="."
      listing="forCompany"
      defaultset="newForCompany"
      defaultsetparams="." />

8.3. When to Use

Use ei x set when...Use <embeddedlisting> when...
Few detail records (< 10)Many detail records
Direct inline editing neededRecords edited in separate form
Detail is integral part of masterDetail is reference/history
Examples: invoice lines, addressesExamples: order history, emails

9. Actions

Actions add functionality to forms and listings, allowing users to invoke related entities or custom code through buttons, links, and other widgets.

9.1. Action Locations

The location attribute determines where the action appears:

LocationDescription
formBottom of the entity form
listingBottom of the listing (for batch operations)
localPer-row in the listing
mainTriggered on double-click to open
local,formBoth in listing rows and form

9.2. Action Types

Opens another entity's form, typically used to invoke a transient entity for processing.

Invoice @Invoices
   <action name="sendEmail" label="Send Email" type="relatedentity"
           entity="SendInvoiceEmail" location="local" defaultset="forInvoice" />

SendInvoiceEmail @ transient="transient"
   <defaultset name="forInvoice">
      <param name="invoice" entity="Invoice" />
      <default name="invoice" value="invoice" />
      <default name="recipient" value="invoice.customer.email" />
   </defaultset>

   invoice Invoice fixed
   recipient
   subject
   body text

For batch operations on multiple records:

Company @Companies
   <action name="deactivate" label="Deactivate Selected" location="listing"
           type="relatedentity" entity="DeactivateCompanies" defaultset="forCompanies" />

DeactivateCompanies @ transient="transient"
   <defaultset name="forCompanies">
      <param name="companies" entity="Company" collection="set" />
      <default name="companies" value="companies" />
   </defaultset>

   <html>Warning! These companies will be deactivated:</html>
   companies set Company fixed

9.2.2. Open Entity Actions (type="openentity")

Opens the form of a related entity for viewing/editing. Always used as a property action.

Invoice @Invoices
   customer Customer d \
      <action type="openentity" label="View Customer" />

9.2.3. JavaScript Actions (type="javascript")

Invokes a custom JavaScript function.

Basic example:

Payment @Finance
   <action name="printReceipt" label="Print Receipt" type="javascript"
           function="printReceipt" location="local,form" />

In Main.js:

function printReceipt(obj, id) {
   window.open('../files/receipt.jsp?id=' + id);
}

With parameters:

Auction @Auctions
   vehicle Vehicle
   <action name="editVehicle" label="Edit Vehicle" type="javascript"
           function="editVehicle" location="local" functionparams="vehicle.@id" />

The function receives the standard arguments (obj, ids) followed by one argument per entry in functionparams: function editVehicle(obj, ids, vehicleId) { ... }.

9.3. Property Actions

Property actions are defined inline with a property using the \ continuation character:

Invoice
   customer Customer d \
      <action type="openentity" label="View" />
   address text \
      <action name="viewMap" type="javascript" function="viewOnMap" label="View on Map" />

9.4. Action Groups

When you have many actions, group them in a dropdown menu using <actiongroup>:

Case @Cases
   <actiongroup name="actions" label="Actions" location="local">
      <action name="viewAccount" label="View Account" entity="ViewAccount"
              type="relatedentity" defaultset="forCase" icon="24" />
      <action name="settle" label="Settle" entity="Settle"
              type="relatedentity" defaultset="forCase" icon="f1ec" />
      <action name="notify" label="Notify" entity="Notify"
              type="relatedentity" defaultset="forCase" icon="f0e0" />
   </actiongroup>

Note: Actions inside <actiongroup> don't need the location attribute since it's defined on the group.

9.5. Conditional Action Display

Use displayclass to show/hide actions based on entity state:

In the entity definition:

ExpenseDetail @Payments
   <action name="viewInvoice" label="View Invoice" type="javascript"
           function="viewInvoice" location="local,form" displayclass="invoiced" />

In the Java entity class:

public String getCssClass() {
   StringBuilder cssClass = new StringBuilder();
   cssClass.append(getInvoice() == null ? "notInvoiced" : "invoiced");
   return cssClass.toString();
}

Generated in Rules.css:

#action_ExpenseDetail_viewInvoice { display: none; }
.invoiced #action_ExpenseDetail_viewInvoice { display: inline-block; }

9.6. Action Attributes Summary

AttributeDescription
nameAction identifier
labelDisplay text
typerelatedentity, openentity, or javascript
entityTarget entity (for relatedentity)
locationWhere to display: form, listing, local, main
defaultsetDefaultset to initialize the target entity
functionJavaScript function name (for javascript type)
functionparamsParameters to pass to the function
iconIcon code to display
displayclassCSS class for conditional display
widgetWidget type (e.g., "button")

10. Defaultsets

Defaultsets define how to initialize an entity's fields when creating a new record from a related context.

10.1. Basic Usage

Person @Persons
   <defaultset name="newForCompany">
      <param name="company" entity="Company" />
      <default name="company" value="company" />
      <default name="country" value="company.country" />
   </defaultset>

   name d r
   company Company
   country Country

10.2. Defaultset Components

<param> - Declares an input parameter:

AttributeDescription
nameParameter name
entityEntity type of the parameter
typePrimitive type (if not an entity)
collectionCollection type: set or list

<default> - Sets a field's default value:

AttributeDescription
nameField to set
valueValue or expression

10.3. Using Defaultsets

In embedded listings:

Company
   <embeddedlisting name="employees" entity="Person" subset="forCompany"
                    subsetparams="." defaultset="newForCompany" defaultsetparams="." />

In actions:

Company
   <action name="newPerson" label="New Person" type="relatedentity"
           entity="Person" defaultset="newForCompany" location="local" />

10.4. Collection Parameters

For batch operations, use collection parameters:

DeactivateCompanies @ transient="transient"
   <defaultset name="forCompanies">
      <param name="companies" entity="Company" collection="set" />
      <default name="companies" value="companies" />
   </defaultset>

   companies set Company fixed
   reason text

Defaultsets can access nested properties using dot notation:

SendEmail @ transient="transient"
   <defaultset name="forPerson">
      <param name="person" entity="Person" />
      <default name="person" value="person" />
      <default name="recipient" value="person.email" />
      <default name="greeting" value="person.firstName" />
   </defaultset>

11. Conditions

Conditions define the criteria for filtering records in subsets, filters, and other contexts.

11.1. Condition Tags

TagDescription
<condition>Simple field-based condition
<restriction>Complex SQL/HQL expression
<and>All nested conditions must be true
<or>At least one nested condition must be true

11.2. <condition> Attributes

AttributeDescriptionExample
fieldProperty to comparefield="active"
valueEquals valuevalue="true"
gtGreater thangt="minValue"
geGreater than or equalge="startDate"
ltLess thanlt="maxValue"
leLess than or equalle="endDate"
likeSQL LIKE patternlike="concat('%', name, '%')"
isnullField is nullisnull="isnull"
notnullField is not nullnotnull="notnull"
inValue in listin="statusList"
containsCollection contains valuecontains="User:find(userId)"

11.3. Examples

Simple equality:

<subset name="active">
   <condition field="active" value="true" />
</subset>

Date range:

<subset name="thisMonth">
   <condition field="date" ge="DateUtil.startOfMonth(now())" />
   <condition field="date" le="DateUtil.endOfMonth(now())" />
</subset>

Null check:

<subset name="unassigned">
   <condition field="assignee" isnull="isnull" />
</subset>

Collection contains:

<subset name="forCurrentUser">
   <condition field="participants" contains="User:find(userId)" />
</subset>

11.4. <restriction> Tag

Use <restriction> for complex SQL/HQL expressions:

<subset name="forProduct">
   <param name="product" entity="Product" />
   <restriction expr="EXISTS (FROM InvoiceLine il WHERE il.invoice = me AND il.product = ?)">
      <param value="product" />
   </restriction>
</subset>

Multiple parameters:

<subset name="inDateRange">
   <param name="startDate" type="date" />
   <param name="endDate" type="date" />
   <restriction expr="date BETWEEN ? AND ?">
      <param value="startDate" />
      <param value="endDate" />
   </restriction>
</subset>

11.5. Combining Conditions

Using <and> (implicit when conditions are at the same level):

<subset name="activeAndRecent">
   <condition field="active" value="true" />
   <condition field="createdDate" ge="DateUtil.addDays(now(), -30)" />
</subset>

Using <or>:

<subset name="visibleToUser">
   <or>
      <condition field="owner" value="User:find(userId)" />
      <condition field="public" value="true" />
      <condition field="sharedWith" contains="User:find(userId)" />
   </or>
</subset>

Combining <and> and <or>:

<subset name="complex">
   <condition field="active" value="true" />
   <or>
      <condition field="priority" value="high" />
      <and>
         <condition field="dueDate" lt="now()" />
         <condition field="status" value="pending" />
      </and>
   </or>
</subset>

12. Enums

JFaster supports enumerations for fields with a fixed set of values.

12.1. Defining Enumsets

Define an enumset at the top of your file:

<enumset name="Priority">
   <enum value="low">Low</enum>
   <enum value="medium">Medium</enum>
   <enum value="high">High</enum>
   <enum value="critical">Critical</enum>
</enumset>

<enumset name="Status">
   <enum value="draft">Draft</enum>
   <enum value="pending">Pending Review</enum>
   <enum value="approved">Approved</enum>
   <enum value="rejected">Rejected</enum>
</enumset>

12.2. Using Enums in Properties

Task @Tasks
   title d r
   priority enum enumset="Priority" default="medium"
   status enum enumset="Status" default="draft"

12.3. Enum in Multi-valued Fields

Person @Persons
   name d r
   skills set enum enumset="Skills"

12.4. Inline Enum Definition

For simple cases, define the enum inline:

Contact @Contacts
   name d r
   type enum ds \
      <enum value="customer">Customer</enum>
      <enum value="supplier">Supplier</enum>
      <enum value="partner">Partner</enum>

13. Tabs and Form Layout

13.1. Tabs

Organize form fields into tabs using #tab:

Person @Persons

   #tab label="Personal Info"
      name d r
      lastName d r
      birthdate date
      email

   #tab label="Address"
      street
      city
      country Country
      postalCode

   #tab label="Employment"
      company Company
      position
      startDate date

13.2. Boxes for Layout

Use <box> to create column layouts:

Invoice @Invoices

   #tab label="Details"
      <box class="cols">
         <box>
            invoiceNumber d fixed
            invoiceDate date ds
            dueDate date
         </box>
         <box>
            customer Customer d
            status ds
            total double ds
         </box>
      </box>

      <embeddedlisting name="lines" entity="InvoiceLine" subset="forInvoice" subsetparams="." />

13.3. HTML Content

Add custom HTML to forms:

Company @Companies
   name d r

   <html><![CDATA[<h3>Contact Information</h3>]]></html>
   phone
   email
   website

   <html><![CDATA[<hr/><h3>Employees</h3>]]></html>
   <embeddedlisting name="employees" entity="Person" subset="forCompany" subsetparams="." />

14. Generated Code Details

14.1. Java Entity Class

For entity Person, JFaster generates Person.java:

public class Person {
   private Long id;
   private String name;
   private String lastName;
   private Company company;
   private Set<String> emails;

   // Getters and setters
   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }

   // ... etc
}

14.2. Services Class

PersonServices.java provides:

public class PersonServices {
   // Find by ID
   public Person find(String id) { ... }

   // Find page (for listings)
   public Collection<Person> findPage() { ... }

   // Store (create or update)
   public Long store(String id, Person obj) { ... }

   // Subset methods
   public Collection<Person> findSubsetForCompany(Company company) { ... }
}

14.3. DAO Methods

The DAO provides additional query methods:

public interface PersonDAO {
   // Find single record by property
   Person findOneBy(String property, Object value);

   // Find multiple records by property
   Collection<Person> findManyBy(String property, Object value);

   // Example usage:
   // Person p = personDAO.findOneBy("email", "john@example.com");
   // Collection<Person> employees = personDAO.findManyBy("company", company);
}

14.4. REST API Endpoints

MethodEndpointDescription
GET/xml/PersonList all (paginated)
GET/xml/Person/{id}Get by ID
POST/xml/Person/{id}Create/Update
GET/xml/Person/forCompany/{companyId}Subset query

15. Validation and Exceptions

15.1. Server-Side Validation

Override the validate() method in your entity class:

public class Person {

   @Override
   public void validate() throws ServiceException {
      if (getAge() != null && getAge() < 0) {
         throw new ServiceException("Age cannot be negative");
      }
      if (getEmail() != null && !getEmail().contains("@")) {
         throw new ServiceException("Invalid email format");
      }
   }
}

15.2. Exception Types

ExceptionDescriptionUI Behavior
ServiceExceptionValidation errorShows error message
ConfirmationExceptionRequires user confirmationShows confirmation dialog
PromptExceptionRequires user inputShows input prompt

ConfirmationException example:

public Long store(String id, Person person) throws ServiceException {
   if (person.getAge() > 100) {
      throw new ConfirmationException("Age is over 100. Are you sure this is correct?");
   }
   // Continue with save...
}

PromptException example:

public void deactivate(Company company) throws ServiceException {
   throw new PromptException("Please enter a reason for deactivation:", "reason");
}

16. Customization

16.1. Custom Java

Extending Services:

Override methods in PersonServicesCustom.java:

public class PersonServicesCustom extends PersonServices {

   @Override
   public Long store(String id, Person person) throws ServiceException {
      // Custom logic before save
      person.setLastModified(new Date());

      Long result = super.store(id, person);

      // Custom logic after save
      notificationService.notify("Person saved: " + person.getName());

      return result;
   }
}

Custom entity methods:

public class Person {

   public String getFullName() {
      return getName() + " " + getLastName();
   }

   public String getCssClass() {
      if (getActive()) {
         return "active";
      }
      return "inactive";
   }
}

16.3. Custom CSS

In Custom.css:

/* Style specific fields */
#Person_name {
   font-weight: bold;
   font-size: 18px;
}

/* Style based on entity state */
.inactive #Person_form {
   opacity: 0.7;
}

/* Action button styling */
#action_Person_sendEmail {
   background-color: #4CAF50;
   color: white;
}

17. Advanced Features

17.1. Stereotypes

StereotypeDescription
stereotype="Async"Transient entity processed asynchronously
stereotype="Email"Email entity with standard email fields

17.2. Next Actions

Define what happens after saving:

Language @Languages
   <next type="function" function="showConfirmation" />
   name d

17.3. Display Conditions

Control visibility based on related entity data:

Person
   phones sortedset \
      <displaycondition expr="company.active == true">
         <param name="company" entity="Company" value="company" />
      </displaycondition>

17.4. Dynamic Values

Automatically compute field values:

InvoiceLine
   product Product
   quantity integer
   unitPrice double \
      <dynamicvalue expr="product.price">
         <param name="product" entity="Product" value="product" />
      </dynamicvalue>
   total double \
      <dynamicvalue expr="unitPrice * quantity">
         <param name="unitPrice" type="double" value="unitPrice" />
         <param name="quantity" type="integer" value="quantity" />
      </dynamicvalue>

17.5. Widgets

Available widgets for properties:

WidgetDescription
widget="jdatepicker"Date picker
widget="html"Rich text editor
widget="select"Dropdown select (for booleans)
widget="checkbox"Checkbox group (for sets)
widget="radio"Radio button group

18. How-To Guides

18.2. Adding Conditional Field Display

Show field based on another field's value:

Person
   hasSpouse boolean "Married?"
   spouseName displayif="hasSpouse = 'true'"

18.3. Creating Dependent Dropdowns

Country → Province → City cascade:

Country @Config
   name d

Province @Config
   <subset name="forCountry">
      <param name="country" entity="Country" />
      <condition field="country" value="country" />
   </subset>
   name d
   country Country

City @Config
   <subset name="forProvince">
      <param name="province" entity="Province" />
      <condition field="province" value="province" />
   </subset>
   name d
   province Province

Person @Persons
   name d r
   country Country
   province Province subset="forCountry" subsetparams="country"
   city City subset="forProvince" subsetparams="province"

18.4. Implementing Master-Detail

Order @Orders
   orderNumber d fixed formula="id"
   orderDate date default="now" ds
   customer Customer d r
   lines OrderLine set ei x childproperty="order"
   total double ds formula="(SELECT SUM(quantity * price) FROM order_line WHERE order_id = id)"

OrderLine @
   order Order
   product Product d
   quantity integer r
   price double \
      <dynamicvalue expr="product.price">
         <param name="product" entity="Product" value="product" />
      </dynamicvalue>

18.5. Working with Files

Document @Documents
   name d r
   file file r
   uploadDate datetime default="now" fixed ds

Files are stored in the configured upload directory and the path is saved in the database.

Product @Products
   <filter name="search" label="Search" display="primary">
      <or>
         <condition field="name" like="concat('%', search, '%')" />
         <condition field="description" like="concat('%', search, '%')" />
         <condition field="code" like="concat('%', search, '%')" />
      </or>
   </filter>

   code d
   name d r
   description text

18.7. Batch Operations

Product @Products
   <action name="updatePrices" label="Update Prices" location="listing"
           type="relatedentity" entity="UpdatePrices" defaultset="forProducts" />

UpdatePrices @ transient="transient"
   <defaultset name="forProducts">
      <param name="products" entity="Product" collection="set" />
      <default name="products" value="products" />
   </defaultset>

   products set Product fixed
   percentageIncrease double "Increase %"

19. Database Support

JFaster supports multiple databases:

DatabaseConfiguration
MySQLDefault, fully supported
PostgreSQLSupported
OracleSupported
SQL ServerSupported

Configure in hibernate.cfg.xml:

<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/mydb</property>

Appendix A: Quick Reference

Property Shortcuts

ShorthandFull Form
rrequired="required"
ddisplay="primary"
dsdisplay="secondary"
hiddenhidden="hidden"
fixedfixed="fixed"

Common Patterns

Basic entity with menu:

EntityName @MenuName
   field1 d r
   field2 type

Entity with relationship:

Child
   parent Parent

Master/detail:

Master
   details Detail set ei x childproperty="master"

Transient action entity:

DoSomething @ transient="transient"
   <defaultset name="forEntity">
      <param name="entity" entity="Entity" />
      <default name="entity" value="entity" />
   </defaultset>
   entity Entity fixed