๐Ÿ”ท Core

ortus-java-coding-standards

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.

$ npx skills add ortus-solutions/skills/ortus-java-coding-standards
$ coldbox ai skills install ortus-solutions/skills/ortus-java-coding-standards
๐Ÿ”— https://skills.boxlang.io/skills/raw/ortus-solutions/skills/ortus-java-coding-standards

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.
// Java โ€” tab-indented, end-of-line braces
public class UserService {

    public User findById( int id ) {
        if ( id <= 0 ) {
            throw new IllegalArgumentException( "id must be positive" );
        }
        return repository.find( id );
    }

}
// BoxLang โ€” same indentation rules
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
// Java
public void process( String name, int count ) {
    if ( count > 0 ) {
        doThing( name );
    }
    var result = ( String ) rawValue;
}
// BoxLang
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 (:

// WRONG
doThing ( name );

// RIGHT
doThing( name );

No space inside empty parentheses:

// RIGHT
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.

// RIGHT
public void save( User user ) {
    if ( user.isValid() ) {
        repository.save( user );
    } else {
        throw new ValidationException( "invalid user" );
    }
}

// WRONG โ€” Allman style, do not use
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.

// WRONG โ€” no braces, body on same line
if ( user == null ) return;

for ( var item : items ) process( item );

// RIGHT
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 :)
// Java
var total  = price * quantity;
var result = isValid ? "yes" : "no";
var upper  = items.stream().map( s -> s.toUpperCase() ).collect( Collectors.toList() );
// BoxLang
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
// Java โ€” aligned field declarations
private final UserRepository  userRepository;
private final EmailService    emailService;
private final int             maxRetries;
// BoxLang โ€” aligned assignments
var firstName = "Alice"
var lastName  = "Smith"
var email     = "[email protected]"
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

ContextRule
Between methods1 blank line
Between abstract methods1 blank line
Between fields0 blank lines (fields are grouped together)
After package declaration1 blank line
First declaration inside a class body1 blank line
Beginning of a method body0 blank lines
End of a code block0 blank lines
Before a code block (e.g., before {)0 blank lines
// Java โ€” correct blank line usage
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

ItemConventionExample
Java classesPascalCaseUserService, OrderProcessor
Java interfacesPascalCaseUserRepository, Serializable
Java methodscamelCasegetUserById(), processOrder()
Java fieldscamelCaseuserRepository, maxRetries
Java constantsUPPER_SNAKE_CASEMAX_RETRIES, DEFAULT_TIMEOUT
Java packageslowercase.dot.separatedortus.boxlang.runtime.services
BoxLang classesPascalCaseUserService.bx, OrderProcessor.bx
BoxLang functionscamelCasegetUserById(), processOrder()
BoxLang variablescamelCaseuserProfile, orderTotal
BoxLang templatescamelCase or kebab-caseuserProfile.bxm, order-detail.bxm
BoxLang scriptscamelCasebuildReport.bxs
BoxLang constants (local)UPPER_SNAKE_CASEvar MAX_RETRIES = 3

Comments and Javadoc

Javadoc (Java)

Write Javadoc for all public classes and public/protected methods.

/**
 * Finds a user by their unique identifier.
 *
 * @param  id  the user's primary key (must be positive)
 *
 * @return the matching {@link User}, or {@code null} if not found
 *
 * @throws IllegalArgumentException if {@code id} is not positive
 */
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)

// Use single-line comments for brief explanations above the line they describe.
// Never end-of-line comments for non-obvious things โ€” put them above instead.

// Calculate total including tax
var total = basePrice * ( 1 + taxRate );

Do not leave commented-out code in committed files.

BoxLang Documentation Comments

/**
 * Finds a user by their unique identifier.
 *
 * @id         The user's primary key. Must be a positive integer.
 * @return     struct containing user data, or an empty struct if not found.
 */
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.

// RIGHT โ€” no semicolons
var result = calculate( x, y )
return result

// WRONG
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:

// Lambda โ€” only uses the item argument (no outer scope access)
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:

// Closure โ€” accesses outer variable `threshold`
var filtered = numbers.filter( ( n ) => n > threshold )

// Closure โ€” calls external BIF
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:

// WRONG โ€” arguments.name refers to the closure's arguments, not the outer function's
function process( required string name ) {
    var found = items.filter( ( item ) => item.name != arguments.name )
}

// RIGHT โ€” use unscoped name; BoxLang finds it in the enclosing scope
function process( required string name ) {
    var found = items.filter( ( item ) => item.name != name )
}

Function Call Spacing

// RIGHT โ€” spaces inside parentheses, space after comma
doThing( arg1, arg2 )
createUser( firstName = "Alice", active = true )

// WRONG โ€” no spaces inside parens
doThing(arg1, arg2)

Struct and Array Literals

// Preferred โ€” literal syntax with alignment
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:

// Java
var result = userService.createUser(
    request.getFirstName(),
    request.getLastName(),
    request.getEmail(),
    request.getRoleId()
);
// BoxLang
var result = userService.createUser(
    firstName = request.firstName,
    lastName  = request.lastName,
    email     = request.email,
    roleId    = request.roleId
)

Wrap before operators, not after:

// RIGHT โ€” operator at start of wrapped line
var isEligible = user.isActive()
    && user.hasVerifiedEmail()
    && !user.isSuspended();

Java-Specific Patterns

Import Order

Group imports in this order with one blank line between groups:

  1. java.* and javax.*
  2. Third-party libraries
  3. 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:

// WRONG
if ( retries > 3 ) { ... }

// RIGHT
private static final int MAX_RETRIES = 3;
if ( retries > MAX_RETRIES ) { ... }

Common Anti-Patterns to Avoid

Anti-PatternFix
Allman-style bracesUse K&R (end-of-line) braces
No spaces inside ( ) in callsAlways doThing( arg ) not doThing(arg)
Semicolons on BoxLang statementsRemove unless a property declaration
Unaligned field groupsAlign with spaces/tabs to column
arguments.name inside closure accessing outer scopeRemove scope prefix
Comment-out dead codeDelete it; use version control
Wildcard imports in JavaUse explicit imports
Magic numbersExtract to named constants
Mutable public fields in JavaUse private final + accessor
One-liner if without bracesAlways use braces