3Examples of Each Context Where You Can Use Groovy
Examples of Each Context Where You Can Use Groovy
This section provides a simple example of using Groovy in all of the different supported contexts in your application.
Providing an Expression to Calculate a Custom Formula Field's Value
To compute a field’s value using an formula, set the field’s Value Calculation property to Calculate value with a formula and provide an appropriate Groovy expression.
Read-Only Calculated Fields
A field whose value calculation is configured to use a formula is read-only. The expression you supply is evaluated at runtime to return the field’s value each time it is accessed. The expected return type of the formula field's expression must be compatible with the type of the field on which you’ve configured that formula. (e.g. Number, Date, or String).
For example, consider a custom TroubleTicket
object. If you add a number field named daysOpen
, you can configure it to calculate its value with a formula and provide an expression like this:
(today() - creationDate) as Integer /* truncate to whole number of days */
Providing an Expression to Calculate a Custom Field's Default Value
When a new row is created for an object, the value of a custom field defaults to null
unless you configure a default value for it. You can configure a default by setting its Value Calculation property to supply an expression to Set to default if value not provided. You can either specify a static default value, or use a Groovy expression. The default value expression is evaluated at the time the new row is created. The expected return type of your field's default value expression must be compatible with the field's type (Number, Date, String, etc.)
For example, consider a callbackDate
field in a TroubleTicket
object. If you want the callback back for a new trouble ticket to default to 3 days after it was created, then you can provide a default expression of:
creationDate + 3
Defining a Field-Level Validation Rule
A field-level validation rule is a constraint you can define on any standard or custom field. It is evaluated whenever the corresponding field's value is set. When the rule executes, the field's value has not been assigned yet and your rule acts as a gatekeeper to its successful assignment. The expression (or longer script) you write must return a boolean
value that indicates whether the value is valid. If the rule returns true
, then the field assignment will succeed so long as all other field-level rules on the same field also return true
. If the rule returns false
, then this prevents the field assignment from occurring, the invalid field is visually highlighted in the UI, and the configured error message is displayed to the end user. Since the assignment fails in this situation, the field retains its current value (possibly null
, if the value was null
before), however the UI component in the web page allows the user to see and correct their invalid entry to try again. Your script can use the newValue
keyword to reference the new value that will be assigned if validation passes. To reference the existing field value, use the oldValue
keyword. A field-level rule is appropriate when the rule to enforce only depends on the new value being set.
For example, consider a TroubleTicket
object with a Priority
field. To validate that the number entered is between 1 and 5, your field-level validation rule would look like this:
Field Name: Priority
Rule Name:
Validate_Priority_Range
Error Message:
The priority must be in the range from 1 to 5
Rule Body
newValue == null || (1..5).contains(newValue as Integer)
A
depends on the values of one or more other fields (e.g.
Y
and
Z
), then create an object-level rule and programmatically signal which field or fields should be highlighted as invalid to the user as explained in
Setting Invalid Fields for the UI in an Object-Level Validation Rule.
Defining an Object-Level Validation Rule
An object-level validation rule is a constraint you can define on any business object. It is evaluated whenever the framework attempts to validate the object. Use object-level rules to enforce conditions that depend on two or more fields in the object. This ensures that regardless of the order in which the user assigns the values, the rule will be consistently enforced. The expression (or longer script) you write must return a boolean
value that indicates whether the object is valid. If the rule returns true
, then the object validation will succeed so long as all other object-level rules on the same object return true
. If the rule returns false
, then this prevents the object from being saved, and the configured error message is displayed to the end user.
For example, consider a TroubleTicket
object with Priority
and DueDate
fields. To validate that a trouble ticket of priority 1 or 2 cannot be saved without a due date, your object-level rule would look like this:
Rule Name:
Validate_High_Priority_Ticket_Has_DueDate
Error Message:
A trouble ticket of priority 1 or 2 must have a due date
Rule Body
// Rule depends on two fields, so must be written as object-level rule if (Priority <= 2 && DueDate == null) { // Signal to highlight the DueDate field on the UI as being in error adf.error.addAttribute('DueDate') return false } return true
Defining Reusable Behavior with an Object Function
Object functions are useful for code that encapsulates business logic specific to a given object. You can call object functions by name from any other script code related to the same object or from any other scripts that work programmatically with the object in question. When defining a function, you specify a return value and can optionally specify one or more typed parameters that the caller will be required to pass in when invoked. The most common types for function return values and parameters are the following:
String
: a text valueBoolean
: a logicaltrue
orfalse
valueLong
: an integer value in the range of ±263-1BigInteger
: a integer of arbitrary precisionDouble
: a floating-point decimal value in the range of ±1.79769313486231570 x 10308BigDecimal
: a decimal number of arbitrary precisionDate
: a date value with optional time componentList
: an ordered collection of objectsMap
: an unordered collection of name/value pairsObject
: any object
In addition, a function can define a void
return type which indicates that it returns no value.
For example, you might define the following updateOpenTroubleTicketCount()
object function on a Contact
object. It calls the newView()
built-in function (described in Accessing the View Object for Programmatic Access to Business Objects) to access the view object for programmatic access of trouble tickets, then appends a view criteria to find trouble tickets related to the current contact's id and having either 'Working' or 'Waiting' as their current status. Finally, it calls getEstimatedRowCount()
to retrieve the count of trouble tickets that qualify for the filter criteria. Finally, if the new count is different from the existing value of the openTroubleTickets
field, it updates this field’s value to be the new count computed.
Function Name:
updateOpenTroubleTicketCount
Return Type:
void
Parameters: None
Function Definition
// Access the view object for TroubleTicket programmatic access def tickets = newView('TroubleTicket') tickets.appendViewCriteria(""" contact = ${Id} and status in ('Working','Waiting') """ // Update OpenTroubleTickets field value def newCount = tickets.getEstimatedRowCount() if (openTroubleTickets != newCount) { openTroubleTickets = newCount }
Enabling External Visibility of an Object Function
When you create an object function named doSomething()
on an object named Example
, the following is true by default:
other scripts on the same object can call it,
any script written on another object that obtains a row of type
Example
can call itexternal systems working with an
Example
object via REST service, cannot call itit displays in the Object category of the Functions tab on the Code Helpers Palette.
If you check the Callable by External Systems checkbox, then an external system working with an Example
object will be able to invoke your doSomething()
via REST service. Do this when the business logic it contains should be accessible to external systems.
Defining an Object-Level Trigger to Complement Default Processing
Triggers are scripts that you can write to complement the default processing logic for a standard or custom object. You can define triggers both at the object-level and the field-level. The object-level triggers that are available are described below. See Defining a Field-Level Trigger to React to Value Changes for the available field-level triggers.
On Initialize
Fires when a new instance of an object is created. Use to assign programmatic default values to one or more fields in the object.
On Invalidate
Fires on a valid parent object when a child row is created, removed, or modified, or also when the first persistent field is changed in an unmodified row.
On Remove
Fires when an attempt is made to delete an object. Returning false stops the row from being deleted and displays the optional trigger error message.
Before Insert
Fires before a new object is inserted into the database.
Before Update
Fires before an existing object is modified in the database
Before Delete
Fires before an existing object is deleted from the database
Before Commit
Fires after all changes have been posted to the database, but before they are permanently committed. Can be used to make additional changes that will be saved as part of the current transaction.
Before Rollback
Fires before the change pending for the current object (insert, update, delete) is rolled back
For example, consider a Contact
object with a openTroubleTickets
field that needs to be updated any time a trouble ticket is created or modified. You can create the following trigger on the TroubleTicket
object that invokes the updateOpenTroubleTicketCount()
object function described above.
Trigger Object:
TroubleTicket
Trigger: Before Commit
Trigger Name:
Before_Commit_Set_Open_Trouble_Tickets
Trigger Definition
// Get the related contact for this trouble ticket def relatedContact = contactObject // Update its openTroubleTickets field value relatedContact?.updateOpenTroubleTicketCount()
Defining a Field-Level Trigger to React to Value Changes
Field-level triggers are scripts that you can write to complement the default processing logic for a standard or custom field. The following field-level trigger is available:
After Field Changed
Fires when the value of the related field has changed (implying that it has passed any field-level validation rules that might be present).
Use the After Field Changed trigger to calculate other derived field values when another field changes value. Do not use a field-level validation rule to achieve this purpose because while your field-level validation rule may succeed, other field-level validation rules may fail and stop the field's value from actually being changed. Since generally you only want your field-change derivation logic to run when the field's value actually changes, the After Field Changed trigger guarantees that you get this desired behavior.
See Deriving Values of a Field When Other Fields Change Value for tips on using this trigger.
Converting a Trigger to Custom Code
When you create a new trigger, Visual Builder uses the visual editor shown in the figure below. This interface allows you to solve many common use cases with point and click by configuring one or more conditional expressions and one or more actions that should execute if a given condition is true.

As you use the designer interface, Visual Builder keeps the trigger’s equivalent Groovy script in sync. At any time you can peek at a read-only view of the script code by clicking on the Code Editor button in the toolbar. Click again on the Designer toolbar button to return to the visual view. If your trigger requires a small amount of custom Groovy code, use the Custom Groovy Code action as shown below. This action is useful for adding small amounts of manually authored Groovy script inside an otherwise declaratively-configured trigger. For example here we’ve written one line of Groovy code in the “Upcase Subject” custom Groovy code action to uppercase the subject of the trouble ticket being inserted.

If the complexity of your task demands it, or you simply prefer it that way, you can convert any trigger you create into a custom code trigger. While in the read-only code editor view, as shown in the figure below, you can click on the convert to Custom Code Trigger link to change the current trigger into a manually authored script. Once you’ve performed this step, the code editor becomes editable. After performing this step, you have full control over the contents of the current trigger’s groovy script. This conversion is a one-way street, however. A custom code trigger cannot be switched back into visual design mode. You’ll need to create a new trigger to start again with the point-and-click approach in the visual editor.
