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:
| File | Description |
|---|---|
src/main/webapp/Main/Person_form.html | A 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.html | A 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.java | Entity class with all fields, getters, and setters |
src/main/java/com/my/package/services/PersonServices.java | Service 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.java | DAO interface |
src/main/java/com/my/package/dao/hibernate/HibernatePersonDAO.java | Hibernate DAO implementation |
src/main/resources/com/my/package/dao/hibernate/Person.hbm.xml | Hibernate mapping file |
2.2. Generated REST API
For each entity, REST services are generated. For example, for the entity Person:
| Endpoint | Method | Description |
|---|---|---|
GET /xml/Person | PersonServices.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:
| Endpoint | Description |
|---|---|
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:
- Persistent entities use NOUNS:
Person,Product,Sale,Property,Receipt, etc. - Transient entities use VERBS:
SendEmail,GenerateStatement,PrepareSale,RateProperty, etc.
Example of a transient entity:
SendEmail transient="transient" menu="Actions"
person Person fixed
subject
body text
Transient entities are useful for:
- Processing actions that don't need to be stored
- Wizards and multi-step forms
- Batch operations on multiple records
- Async operations (with
stereotype="Async")
3.2. Entity Attributes
| Attribute | Description |
|---|---|
menu="MenuName" | Places the entity in a specific menu group |
@MenuName | Shorthand 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):
| Type | Java | SQL |
|---|---|---|
integer | int | INT |
long | long | BIGINT |
double | double | DOUBLE |
float | float | FLOAT |
boolean | boolean | BIT(1) |
date | GregorianCalendar | DATE |
datetime | GregorianCalendar | DATETIME |
string | String | VARCHAR(255) |
text | String | TEXT |
longtext | String | LONGTEXT |
file | String | VARCHAR(255) |
image | String | VARCHAR(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:
| Type | Java Mapping | Description |
|---|---|---|
set | Set / HashSet | Unordered, unique values |
sortedset | SortedSet / TreeSet | Sorted, unique values |
list | List / ArrayList | Ordered, allows duplicates |
Additional attributes:
setcan usesetorder="xxx"to tell Hibernate how to order the setsortedsetcan usesortexpr="expression"for custom sortingsortedsetcan usesort="com.package.ComparatorClass"for a custom comparator
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:
person_emails(person BIGINT(20) references person(id), emails VARCHAR(255))person_countries(person BIGINT(20) references person(id), countries BIGINT(20) references country(id))
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.
| Attribute | Meaning | Description |
|---|---|---|
ei | embedded="inline" | The secondary entity is displayed within the master's form |
x | extendable="extendable" | New rows can be added (some cases may want fixed rows) |
set | Collection type | Specifies the relationship is one-to-many |
childproperty="field" | Back-reference | The 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:
| Attribute | Description |
|---|---|
list | Use 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:
| Feature | ei x set | <embeddedlisting> |
|---|---|---|
| Display | Embedded form with inline editing | Listing table within the form |
| Best for | Small number of detail records | Large number of detail records |
| Editing | Direct inline editing | Opens separate form for each record |
| Adding records | Inline with x (extendable) | Via "Add" button in listing |
| Use case | Invoice lines, addresses | Order 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:
| Attribute | Shorthand | Description |
|---|---|---|
required="required" | r | Field is mandatory |
display="primary" | d | Field is shown in listings and as entity description |
display="secondary" | ds | Field is shown in listings but not as primary description |
hidden="hidden" | hidden | Field is not shown in forms |
invisible="invisible" | invisible | Field is completely hidden (not even in HTML) |
disabled="disabled" | disabled | Field is shown but cannot be edited |
fixed="fixed" | fixed | Field is displayed as read-only text (not an input) |
readonly="readonly" | readonly | Input is read-only |
transient="transient" | transient | Field is not persisted to database |
Conditional behavior:
| Attribute | Description |
|---|---|
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
| Attribute | Description | Example |
|---|---|---|
"Label" | Custom label (after property name) | firstName "First Name" |
style="..." | Inline CSS styles | style="width:300px;" |
class="..." | CSS class | class="highlighted" |
maxlength="n" | Maximum input length | maxlength="100" |
minlength="n" | Minimum input length | minlength="5" |
tooltip="text" | Hover tooltip | tooltip="Enter weight in kg" |
widget="type" | Custom widget | widget="jdatepicker" |
4.7. Advanced Property Features
| Feature | Description |
|---|---|
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 |
autosuggest | Enables 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
| Attribute | Description | Example |
|---|---|---|
order="field [asc|desc]" | Sort order for results | order="name asc" |
displayproperties="a,b,c" | Properties to show in dropdowns | displayproperties="name,code" |
displayset="name" | Alternative display configuration | displayset="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:
| Attribute | Description |
|---|---|
name | Internal filter name (convention: same as property) |
property | The entity property to filter on |
label | Display label for the filter |
display | Location: "primary" (visible) or "secondary" (advanced filters) |
type | Data type for filter input |
widget | Custom 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
| Attribute | Description |
|---|---|
name | Listing 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:
| Attribute | Description |
|---|---|
name | Tab identifier |
label | Display text |
subset | Subset to filter records |
displayactions | Actions 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
| Attribute | Description |
|---|---|
name | Identifier for the embedded listing |
entity | The entity to display |
subset | Subset to filter records |
subsetparams | Parameters to pass to the subset (. = current entity) |
listing | Which listing configuration to use |
defaultset | Defaultset for new records |
defaultsetparams | Parameters 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 needed | Records edited in separate form |
| Detail is integral part of master | Detail is reference/history |
| Examples: invoice lines, addresses | Examples: 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:
| Location | Description |
|---|---|
form | Bottom of the entity form |
listing | Bottom of the listing (for batch operations) |
local | Per-row in the listing |
main | Triggered on double-click to open |
local,form | Both in listing rows and form |
9.2. Action Types
9.2.1. Related Entity Actions (type="relatedentity")
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 thelocationattribute 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
| Attribute | Description |
|---|---|
name | Action identifier |
label | Display text |
type | relatedentity, openentity, or javascript |
entity | Target entity (for relatedentity) |
location | Where to display: form, listing, local, main |
defaultset | Defaultset to initialize the target entity |
function | JavaScript function name (for javascript type) |
functionparams | Parameters to pass to the function |
icon | Icon code to display |
displayclass | CSS class for conditional display |
widget | Widget 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:
| Attribute | Description |
|---|---|
name | Parameter name |
entity | Entity type of the parameter |
type | Primitive type (if not an entity) |
collection | Collection type: set or list |
<default> - Sets a field's default value:
| Attribute | Description |
|---|---|
name | Field to set |
value | Value 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
10.5. Accessing Related Properties
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
| Tag | Description |
|---|---|
<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
| Attribute | Description | Example |
|---|---|---|
field | Property to compare | field="active" |
value | Equals value | value="true" |
gt | Greater than | gt="minValue" |
ge | Greater than or equal | ge="startDate" |
lt | Less than | lt="maxValue" |
le | Less than or equal | le="endDate" |
like | SQL LIKE pattern | like="concat('%', name, '%')" |
isnull | Field is null | isnull="isnull" |
notnull | Field is not null | notnull="notnull" |
in | Value in list | in="statusList" |
contains | Collection contains value | contains="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
| Method | Endpoint | Description |
|---|---|---|
GET | /xml/Person | List 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
| Exception | Description | UI Behavior |
|---|---|---|
ServiceException | Validation error | Shows error message |
ConfirmationException | Requires user confirmation | Shows confirmation dialog |
PromptException | Requires user input | Shows 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
| Stereotype | Description |
|---|---|
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:
| Widget | Description |
|---|---|
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.
18.6. Implementing Search
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:
| Database | Configuration |
|---|---|
| MySQL | Default, fully supported |
| PostgreSQL | Supported |
| Oracle | Supported |
| SQL Server | Supported |
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
| Shorthand | Full Form |
|---|---|
r | required="required" |
d | display="primary" |
ds | display="secondary" |
hidden | hidden="hidden" |
fixed | fixed="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