| name | ortus-coding-standards |
| description | Use this skill when writing, reviewing, or formatting any Ortus Solutions code (BoxLang, CFML, or Java) to ensure it follows the official Ortus coding standards: indentation, spacing, brace placement, naming, alignment, comments, and structural conventions. |
Ortus Coding Standards
Overview
Ortus Solutions maintains consistent formatting rules across all BoxLang, CFML, and Java
source code. These rules are enforced via the OrtusJava Eclipse formatter profile
(ortus-java-style.xml) for Java, and via the conventions documented here for BoxLang
and CFML. When in doubt, match what already exists in the file you are editing.
Indentation
Use tabs for indentation — never spaces for the leading indent.
- Class body: indented one tab from the class declaration.
- Method body: indented one tab from the method signature.
- Switch cases: indented one tab from
switch.
- Case body: indented one tab from the
case label.
- Continuation lines (wrapped expressions): indented one level.
public class UserService {
public User findById( int id ) {
if ( id <= 0 ) {
throw new IllegalArgumentException( "id must be positive" );
}
return repository.find( id );
}
}
class UserService {
function findById( required numeric id ) {
if ( id <= 0 ) {
throw( type = "InvalidArgument", message = "id must be positive" )
}
return variables.repository.find( arguments.id )
}
}
Spacing Inside Parentheses
Always place a space after ( and before ) in:
- Method declarations
- Method invocations
- Control flow keywords (
if, for, while, switch, catch, synchronized)
- Casts
- Parenthesized expressions
public void process( String name, int count ) {
if ( count > 0 ) {
doThing( name );
}
var result = ( String ) rawValue;
}
function process( required string name, required numeric count ) {
if ( count > 0 ) {
doThing( name )
}
}
Never place a space between a function name/keyword and its opening (:
doThing ( name );
doThing( name );
No space inside empty parentheses:
init()
list()
Brace Style
Use K&R / end-of-line brace placement — opening brace on the same line as
the statement, not on its own line.
public void save( User user ) {
if ( user.isValid() ) {
repository.save( user );
} else {
throw new ValidationException( "invalid user" );
}
}
public void save( User user )
{
...
}
The same rule applies to:
- Class declarations
- Method declarations
if / else / else if
for / while / do-while
try / catch / finally
switch
- Array initializers
Always Use Braces
Even for single-statement bodies, always use braces. Never place an if or loop
body on the same line as its condition.
if ( user == null ) return;
for ( var item : items ) process( item );
if ( user == null ) {
return;
}
for ( var item : items ) {
process( item );
}
Spacing Around Operators
Place one space on each side of:
- Assignment operators (
=, +=, -=, etc.)
- Comparison operators (
==, !=, <, >, <=, >=)
- Arithmetic operators (
+, -, *, /, %)
- Bitwise operators (
&, |, ^, ~)
- Shift operators (
<<, >>, >>>)
- String concatenation (
& in BoxLang/CFML, + in Java)
- Lambda arrows (
-> in Java, -> / => in BoxLang)
- Ternary operator (
? and :)
var total = price * quantity;
var result = isValid ? "yes" : "no";
var upper = items.stream().map( s -> s.toUpperCase() ).collect( Collectors.toList() );
var total = price * quantity
var result = isValid ? "yes" : "no"
var upper = items.map( ( s ) -> uCase( s ) )
No space for:
- Unary operators before their operand:
!condition, ++i, -value
- After
!: !isValid (no space between ! and isValid)
- Ellipsis:
String... values (no space before ...)
Column Alignment
When multiple related declarations or assignments appear in a block, align on
columns so they read like a table. This applies to:
- Field (property) declarations
- Local variable declarations
- Assignment groups
private final UserRepository userRepository;
private final EmailService emailService;
private final int maxRetries;
var firstName = "Alice"
var lastName = "Smith"
var email = "alice@example.com"
var active = true
this.name = "My App"
this.sessionManagement = true
this.sessionTimeout = createTimespan( 0, 1, 0, 0 )
this.timezone = "UTC"
Apply alignment within logical groups (separated by blank lines). Do not force
alignment across unrelated declarations.
Blank Lines
| Context | Rule |
|---|
| Between methods | 1 blank line |
| Between abstract methods | 1 blank line |
| Between fields | 0 blank lines (fields are grouped together) |
After package declaration | 1 blank line |
| First declaration inside a class body | 1 blank line |
| Beginning of a method body | 0 blank lines |
| End of a code block | 0 blank lines |
Before a code block (e.g., before {) | 0 blank lines |
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentService paymentService;
public OrderService( OrderRepository orderRepository, PaymentService paymentService ) {
this.orderRepository = orderRepository;
this.paymentService = paymentService;
}
public Order create( CreateOrderRequest request ) {
var order = buildOrder( request );
orderRepository.save( order );
return order;
}
private Order buildOrder( CreateOrderRequest request ) {
return new Order( request.getItems(), request.getUserId() );
}
}
Naming Conventions
| Item | Convention | Example |
|---|
| Java classes | PascalCase | UserService, OrderProcessor |
| Java interfaces | PascalCase | UserRepository, Serializable |
| Java methods | camelCase | getUserById(), processOrder() |
| Java fields | camelCase | userRepository, maxRetries |
| Java constants | UPPER_SNAKE_CASE | MAX_RETRIES, DEFAULT_TIMEOUT |
| Java packages | lowercase.dot.separated | ortus.boxlang.runtime.services |
| BoxLang classes | PascalCase | UserService.bx, OrderProcessor.bx |
| BoxLang functions | camelCase | getUserById(), processOrder() |
| BoxLang variables | camelCase | userProfile, orderTotal |
| BoxLang templates | camelCase or kebab-case | userProfile.bxm, order-detail.bxm |
| BoxLang scripts | camelCase | buildReport.bxs |
| BoxLang constants (local) | UPPER_SNAKE_CASE | var MAX_RETRIES = 3 |
Comments and Javadoc
Javadoc (Java)
Write Javadoc for all public classes and public/protected methods.
public User findById( int id ) {
...
}
Rules:
- Opening
/** and closing */ on their own lines.
- One space after
* on every body line.
@param, @return, and @throws tags on separate lines.
- Do not join description lines — keep each sentence on its own line.
@param descriptions aligned (not required but preferred for readability).
Inline Comments (Java)
var total = basePrice * ( 1 + taxRate );
Do not leave commented-out code in committed files.
BoxLang Documentation Comments
struct function findById( required numeric id ) {
...
}
BoxLang-Specific Conventions
Semicolons
Do not use semicolons on regular statements in BoxLang. They are optional and
the standard is to omit them for cleaner code.
var result = calculate( x, y )
return result
var result = calculate( x, y );
return result;
Exceptions where semicolons ARE required:
- Property declarations:
property name="fieldName" type="string";
- Multiple statements on a single line (avoid this pattern)
Lambdas vs Closures
Use lambdas (->) when the function is deterministic and operates only on
its own arguments:
var doubled = numbers.map( ( n ) -> n * 2 )
var upper = words.map( ( w ) -> w.uCase() )
Use closures (=>) when the function accesses variables from the enclosing
scope or calls external BIFs:
var filtered = numbers.filter( ( n ) => n > threshold )
var encoded = values.map( ( v ) => encodeForHTML( v ) )
Argument Scope in Closures
Inside a closure, do not use the arguments scope to access outer function
parameters. The arguments scope inside the closure refers only to the
closure's own parameters:
function process( required string name ) {
var found = items.filter( ( item ) => item.name != arguments.name )
}
function process( required string name ) {
var found = items.filter( ( item ) => item.name != name )
}
Function Call Spacing
doThing( arg1, arg2 )
createUser( firstName = "Alice", active = true )
doThing(arg1, arg2)
Struct and Array Literals
var config = {
host : "localhost",
port : 5432,
database: "myapp"
}
var roles = [ "admin", "editor", "viewer" ]
Multi-Line Method Calls
When a call does not fit on one line, wrap arguments with one argument per line
and align them:
var result = userService.createUser(
request.getFirstName(),
request.getLastName(),
request.getEmail(),
request.getRoleId()
);
var result = userService.createUser(
firstName = request.firstName,
lastName = request.lastName,
email = request.email,
roleId = request.roleId
)
Wrap before operators, not after:
var isEligible = user.isActive()
&& user.hasVerifiedEmail()
&& !user.isSuspended();
Java-Specific Patterns
Import Order
Group imports in this order with one blank line between groups:
java.* and javax.*
- Third-party libraries
ortus.boxlang.* internal classes
Do not use wildcard imports (import java.util.*).
Null Checks
Prefer Objects.requireNonNull in constructors and public entry points:
public UserService( UserRepository repo ) {
this.repo = Objects.requireNonNull( repo, "repo must not be null" );
}
final Fields
Declare all injected dependencies and constructor-set fields as final:
private final UserRepository userRepository;
private final EmailService emailService;
Avoid Magic Numbers
Extract literal numbers and strings into named constants:
if ( retries > 3 ) { ... }
private static final int MAX_RETRIES = 3;
if ( retries > MAX_RETRIES ) { ... }
Common Anti-Patterns to Avoid
| Anti-Pattern | Fix |
|---|
| Allman-style braces | Use K&R (end-of-line) braces |
No spaces inside ( ) in calls | Always doThing( arg ) not doThing(arg) |
| Semicolons on BoxLang statements | Remove unless a property declaration |
| Unaligned field groups | Align with spaces/tabs to column |
arguments.name inside closure accessing outer scope | Remove scope prefix |
| Comment-out dead code | Delete it; use version control |
| Wildcard imports in Java | Use explicit imports |
| Magic numbers | Extract to named constants |
Mutable public fields in Java | Use private final + accessor |
One-liner if without braces | Always use braces |