For the complete documentation index, see llms.txt. This page is also available as Markdown.

1.14.0

June 3, 2026

BoxLang 1.14.0 is an innovative release that pushes the language forward with first-class dynamic sets, ranges, inner classes, template classes, class references as callable constructors, deep query transformation, JSONPath capabilities and much more. This release closes 65 issues spanning new features, developer experience enhancements, formatter maturity, CFML compatibility parity, and extensive runtime hardening.

This release introduces the Dynamic Set type — a new first-class collection with literal syntax, operator overloads for set algebra, functional pipelines, and three backing variants (hash, linked, sorted). We also introduce the Dynamic Range type, which revolutionizes interval operations with lazy iteration, multiple element types (integers, decimals, characters, dates, and custom IRangeable types), exclusive boundaries, custom stepping, Java Stream integration, and unbounded/half-bounded support. On the language evolution side, inner classes and template classes bring new structural capabilities, while class references now double as callable constructors via functional callbacks. The DataNavigator gains full JSONPath-style query support with get(), has(), and the new query() method. The MiniServer health endpoint now includes Undertow and WebSocket metrics. The formatter becomes even more production-ready with ignore-comment support (@formatter:off / bxformat-ignore-start), multiple-source input, --excludes flag, and fine-grained template.enabled / property_spacing rules. Phew! So much to cover, let's dive in!

🚀 Major Highlights

🔢 Dynamic Set — First-Class Collection Type

BoxLang 1.14.0 introduces BoxSet as a brand-new first-class type, wrapping java.util.Set with full BoxLang integration including member-function dispatch, change listeners, metadata, and JSON serialization. Sets provide a powerful collection model for working with unique values, making them ideal for deduplication, membership testing, tagging systems, permissions, caching, filtering, mathematics, and data comparison workflows.

Unlike arrays, sets enforce uniqueness by design and offer highly efficient lookup operations. BoxLang elevates sets to a first-class citizen with literal syntax, functional collection operations, and rich operator overloads for set algebra—including unions, intersections, differences, and symmetric differences—making complex data manipulation both expressive and concise.

Whether you're comparing datasets, managing unique identifiers, processing large collections, implementing access-control rules, or building recommendation and analytics engines, BoxSet provides a performant and elegant foundation for working with distinct values at scale.

Sets support three backing variants:

  • DEFAULTHashSet, fastest, no ordering

  • LINKEDLinkedHashSet, preserves insertion order

  • SORTEDTreeSet, natural ordering via Compare.invoke

// BIF construction
s = setNew()                                  // empty default (hash)
s = setNew( type="linked", values=[1,2,3] )   // ordered, deduped
s = setOf( 1, 2, 2, 3 )                       // varargs, deduped

// Literal syntax (soft-keyword "set", parser-gated)
s = set{ 1, 2, 3 }                            // default (hash)
s = set{}                                     // empty

// From an Array
s = [1, 2, 3].toSet()
s = [1, 2, 3].toSet( "linked" )

Set algebra via operators:

Rich member-function API — sets support .add(), .contains(), .has(), .remove(), .delete(), .size(), .len(), .isEmpty(), .addAll(), .removeAll(), .retainAll(), .clear(), .containsAll(), .equals(), .isSubsetOf(), .isSupersetOf(), .isDisjointFrom(), .union(), .intersection(), .difference(), .symmetricDifference(), and functional pipelines: .each(), .map(), .filter(), .reject(), .reduce(), .every(), .some(), .none(), .find().

Set Built-In Functions Reference

Construction & Creation

BIF
Member Method
Description

setNew( [type], [values] )

Create a new Set, optionally seeded from a collection

setOf( ...values )

Build a default (hash) Set from positional arguments

toSet( collection, [type] )

Array.toSet(), Query.toSet(), String.listToSet()

Convert a collection into a Set, deduplicating

structKeySet( struct )

Struct.keySet()

Build a Set containing the keys of a Struct

structValueSet( struct )

Struct.valueSet()

Build a Set containing the values of a Struct

Mutation

BIF
Member Method(s)
Description

boxSetAdd( set, value )

.add(), .append()

Add an element — duplicates ignored, returns the Set

boxSetAddAll( set, collection )

.addAll()

Add every element of a collection to a Set

boxSetRemove( set, value )

.remove(), .delete()

Remove an element — returns the Set for chaining

boxSetRemoveAll( set, collection )

.removeAll()

Remove every element of a collection from a Set

boxSetRetainAll( set, collection )

.retainAll()

Retain only elements also present in the collection

boxSetClear( set )

.clear()

Remove all elements, leaving the Set empty

Query & Membership

BIF
Member Method(s)
Description

boxSetContains( set, value )

.contains(), .has()

Test whether a Set contains a given value

boxSetContainsAll( set, collection )

.containsAll()

Test whether a Set contains every element of a collection

boxSetIsEmpty( set )

.isEmpty()

Test whether a Set has no elements

boxSetEquals( setA, setB )

.equals()

Test whether two Sets contain the same elements

boxSetIsSubsetOf( setA, setB )

.isSubsetOf()

Test whether every element of A is also in B

boxSetIsSupersetOf( setA, setB )

.isSupersetOf()

Test whether every element of B is also in A

boxSetIsDisjointFrom( setA, setB )

.isDisjointFrom()

Test whether two Sets share no elements

boxSetFind( set, predicate )

.find()

Return the first element matching the predicate

boxSetEvery( set, predicate )

.every()

True if every element matches the predicate

boxSetSome( set, predicate )

.some(), .any()

True if at least one element matches the predicate

boxSetNone( set, predicate )

.none()

True if no element matches the predicate

Set Algebra

BIF
Member Method
Operator
Description

boxSetUnion( setA, setB )

.union()

+

Compute the union (A ∪ B)

boxSetIntersection( setA, setB )

.intersection()

*

Compute the intersection (A ∩ B)

boxSetDifference( setA, setB )

.difference()

-

Compute the difference (A − B)

boxSetSymmetricDifference( setA, setB )

.symmetricDifference()

^

Compute the symmetric difference (A △ B)

Functional Pipelines

BIF
Member Method
Description

boxSetEach( set, callback )

.each()

Invoke a callback for each element

boxSetMap( set, callback )

.map()

Transform each element, deduplicate results into a new Set

boxSetFilter( set, predicate )

.filter()

Return a new Set of elements matching the predicate

boxSetReject( set, predicate )

.reject()

Return a new Set of elements NOT matching the predicate

boxSetReduce( set, callback, initialValue )

.reduce()

Left-fold with an accumulator function and initial value

Export & Conversion

BIF
Member Method
Description

boxSetToArray( set )

.toArray()

Convert a Set to an Array, preserving iteration order

boxSetToList( set, [delimiter] )

.toList()

Join elements into a delimited string

For a deeper guide on BoxLang sets visit our docs: BoxSet Documentation.

📏 Ranges — Lazy, Typed, Iterable Intervals

BoxLang 1.14.0 introduces Ranges as a first-class type—a massive evolution from the original .. operator that simply materialized arrays. Instead of eagerly generating every value up front, ranges are now lazy, iterable objects that produce values on demand, making them far more memory-efficient, composable, and expressive for everything from loops and data processing pipelines to scheduling, analytics, and domain modeling. oai_citation:0‡Ortus Solutions Community

What makes BoxLang's implementation particularly unique is that ranges are no longer limited to integers. They natively support integers, decimals, characters, dates, and even custom user-defined types through the new IRangeable interface. Developers can create ascending or descending ranges, define custom step increments, use inclusive or exclusive boundaries, build unbounded or half-bounded ranges, perform membership and boundary checks, and seamlessly integrate with Java Streams for high-performance functional processing. oai_citation:1‡Ortus Solutions Community

Unlike many languages where ranges are little more than syntactic sugar for numeric loops, BoxLang elevates ranges into a rich abstraction for representing intervals and sequences of values. Need every day in a month? Every quarter in a fiscal year? Every character from a to z? Every version number, semantic identifier, or business object in a custom progression? Ranges make these operations natural, fluent, and type-safe.

Perhaps the most groundbreaking capability is the introduction of the IRangeable interface, which allows developers to teach BoxLang how to create ranges for their own domain objects. This means you can define ranges over custom types such as software versions, inventory SKUs, workflow states, fiscal periods, geographic coordinates, or any object that has a logical progression. This transforms ranges from a language feature into an extensible framework for modeling real-world sequences and intervals directly in your applications.

By combining lazy evaluation, multiple built-in data types, customizable boundaries and stepping, Java Stream interoperability, and user-extensible range semantics, BoxLang delivers one of the most powerful and flexible range implementations available in any dynamic language today. oai_citation:2‡Ortus Solutions Community

Basic range syntax:

Ranges are not arrays — they're lightweight objects that generate values on demand:

Multiple element types:

Lazy iteration and streaming:

Ranges don't allocate memory for their values — huge ranges are cheap:

Custom stepping:

Contains semantics:

Simple ranges use bounds checks, but stepped ranges verify step-reachability:

Clamping and position checks:

Typed unbounded ranges:

Use .type() to constrain an unbounded range to a specific BoxLang type:

For exact Java class matching with no coercion, pass a Class reference:

Custom rangeable types via IRangeable:

Any BoxLang or Java class can implement ortus.boxlang.runtime.types.IRangeable to participate in ranges:

For a comprehensive guide to BoxLang ranges, including advanced usage patterns and IRangeable implementation details, visit our docs: BoxLang Ranges Documentation.

🧩 Inner Classes and Template Classes

BoxLang now supports classes defined inline within scripts (.bxs), templates (.bxm), or even inside other classes, which enables encapsulation, organization, and scope-local class definitions. These are sometimes called script classes or local classes.

Local classes in .bxs scripts define a named class anywhere in a script file and instantiate it with new. Classes are hoisted, so you can use new before the textual definition:

Local classes in .bxm templates — define a class directly inside a <bx:script> island within a markup template:

Classes that extend other classes — local classes can extend other local classes, abstract classes, and even top-level .bx classes, with full polymorphism:

Local classes with imports — classes inherit their enclosing script's imports, allowing them to use Java types directly:

Inner classes — classes can also be nested inside other classes:

Inner classes are accessed externally via the $ separator syntax — fully qualified, imported, or with aliases:

You can read more about this feature and see additional examples in our docs: Inner Classes Documentation and Template Classes Documentation.

🏗️ Class References as Callable Constructors

BoxLang 1.14.0 introduces a major evolution in object construction by treating class references as first-class callable objects. Whether the class originates from BoxLang or Java, imported class references can now participate directly in the language's functional programming model. This removes much of the ceremony traditionally associated with object creation and opens the door to more expressive, composable, and concise code.

Traditionally, object creation required the new keyword, which remains fully supported. However, class references can now invoke their constructors directly using .init() without requiring new, making object construction feel more natural and consistent with the rest of the language. This is particularly useful when working with dynamically resolved classes, dependency injection scenarios, factory patterns, or APIs that return class references at runtime.

Even more powerful is the introduction of functional constructors, where the class reference itself becomes callable. Invoking a class reference as a function automatically executes the appropriate constructor and returns a new instance. This provides a clean, Python-inspired syntax that reduces noise while preserving full constructor semantics and compatibility with both Java and BoxLang classes.

Beyond syntactic convenience, this feature unlocks entirely new functional programming patterns. Since class references are now callable objects, they can be passed directly to higher-order functions such as map(), reduce(), filter(), and custom functional pipelines. Transforming collections of raw data into fully instantiated objects becomes remarkably concise, allowing developers to express object creation as a first-class operation rather than wrapping constructors in anonymous functions or lambdas.

This capability also strengthens BoxLang's interoperability story. Java classes and BoxLang classes now share a consistent construction model, reducing cognitive overhead when moving between the two ecosystems. Whether you're instantiating a StringBuilder, a custom domain object, or a framework component, the same fluent syntax applies.

Under the hood, class references are wrapped in a specialized ClassInvokerFunction, allowing them to participate in the runtime exactly like any other callable object. Constructor invocation is delegated to the same proven instantiation pipeline used by the new operator, ensuring consistent behavior, compatibility, and performance while dramatically expanding the expressive power of the language.

Class references as functional constructors — the imported class reference itself can be invoked as a function, which executes the constructor and returns an instance. This provides Python-style constructor ergonomics for both Java and BoxLang classes:

Because class references are callable, they can be passed directly to higher-order functions — a clean functional style for mapping data to objects:

Under the hood, class references are wrapped in a ClassInvokerFunction, whose _invoke() delegates to the same constructor plumbing as the new keyword.

🔍 DataNavigator JSONPath Support

What is a DataNavigator? A DataNavigator is BoxLang's fluent helper for safely moving through nested data structures such as Structs, Arrays, parsed JSON, runtime configuration, and metadata. It gives you a consistent API for scoping into data with from(), checking whether values exist with has(), reading values with get(), and applying defaults or strict access rules without scattering null checks throughout your code.

The DataNavigator fluent API gains full JSONPath-style expression support in get(), has(), from(), and the new query() method for multiple-return scenarios. This makes it much easier to inspect, extract, and reshape deeply nested configuration, JSON, API payloads, module metadata, and mixed Array/Struct data without writing repetitive defensive traversal code.

Developers can now use compact path expressions with dot notation, array indexes, slices, wildcards, recursive descent, and filter expressions directly inside the existing navigator workflow. get() remains the best fit when you expect a single value, has() can validate deep paths before use, from() can scope a navigator to a nested segment, and query() returns every match as a BoxLang Array when a path fans out across collections.

This release also adds getOrDefault() for explicit fallback values and getByKey() / hasByKey() for exact-key lookups when real key names contain dots or brackets. Together, these additions make data navigation safer, more expressive, and easier to read, especially in code that consumes external JSON where fields may be optional, irregular, or deeply nested.

Benefits:

  • Less boilerplate for nested Array/Struct traversal

  • Safer handling of optional values with clear fallback behavior

  • Multi-result extraction without manual loops

  • Better support for real-world JSON payloads and configuration documents

  • Exact-key access for data models that use dotted or bracketed key names

Path expression support:

New methods:

All path expressions are whitespace-tolerant — leading, trailing, and separator-adjacent whitespace is ignored.

For the complete guide, examples, and method reference, visit the DataNavigator documentation.

🧵 Query Transformers & Global Query Options

queryExecute() and bx:query are locked into three hardcoded return types: query, array, and struct. Users who want tabular arrays, rich column descriptors, JSON, domain objects, or any other format must post-process results in a separate step. Adding new native return types for every use case is unsustainable.

A powerful new Query Transformer framework (BL-2476) solves this by allowing you to register transformers that process query result sets natively and return exactly what you need — eliminating boilerplate post-processing, since you have access to the full query object and metadata at transformation time.

Three transformer input types:

  1. Closure/Lambda(query, metadata) => any or (query, metadata) → any

  2. Class instance — any class with a transform(query, metadata) method

  3. String — name of a registered transformer from this.queryTransformers in Application.bx

When transformer is provided, it takes precedence over returnType. The transformer receives two arguments:

  • query — the raw Query object (.recordCount, .toArrayOfStructs(), .getData(), .getColumnNames(), etc.)

  • metadata — a struct containing sql, parameters, executionTime, columnMetadata, and more

Transformer Examples

1. Inline Closure — Custom Struct with Metadata

2. Inline Closure — Domain Objects

3. Inline Closure — "Rich" Format with Column Descriptors

4. Inline Closure — "Tabular" Format (Near Zero-Copy)

5. Class Instance Transformer

6. Registered Transformers (Application.bx)

7. Transformer Takes Precedence Over returnType

8. bx:query Component

Global Query Options (BL-2477)

A new queries configuration section in boxlang.json allows global query option defaults, while this.queryOptions = {} in Application.bx provides application-level default query behaviors.

boxlang.json:

Application.bx:

All options can be overridden per query via queryExecute() options or bx:query attributes. Per-query options take highest priority, followed by this.queryOptions, with boxlang.json as the fallback.

✨ New Features

schedulerNew() BIF (BL-2408)

Create and register schedulers directly with a single BIF call — no class file required. Unlike schedulerStart() which requires a class path, schedulerNew() creates a lightweight, ad-hoc scheduler ready for task registration.

Use schedulerNew() for lightweight runtime schedulers. Use schedulerStart() when you need lifecycle callbacks (onStartup, onShutdown, onAnyTaskError) via a dedicated scheduler class.

webMode Server Identifier (BL-1790)

The server scope now exposes a webMode boolean indicating whether the runtime is operating in web (servlet/MiniServer) mode.

New String BIFs: stringStartsWith, stringEndsWith (BL-2439)

Four new Built-In Functions with member-method support for checking string prefix/suffix:

Left/Right Arrow Key REPL Navigation (BL-2409)

The REPL now supports left and right arrow keys for cursor movement within the current input line — a long-requested quality-of-life improvement for interactive development.

Formatter: Multiple File Sources & Excludes (BL-2417, BL-2418)

The boxlang format command now accepts multiple --source files and a new --excludes flag for skipping files or directories:

Formatter: Ignore Comments (BL-2440)

Three styles of formatter-ignore comments are now supported, matching the most popular conventions:

Formatter: template.enabled Flag (BL-2442)

A new formatter config flag template.enabled (defaults to false) gates template (.bxm / .cfm) formatting until it exits experimental mode:

Formatter: property_spacing Rule (BL-2443)

The new class.property_spacing rule (default: 1) controls blank lines between property declarations in class bodies — matching Ortus coding standards with a single blank line between properties.

Pretty Print Config Clone (BL-2422)

The Config object now supports .clone(), enabling safe configuration mutation for multi-pass formatting and tooling scenarios without side effects.

ResolvedFilePath Dump Template (BL-2428)

ResolvedFilePath instances now render with a dedicated HTML dump template showing mapping name, mapping path, relative path, and absolute path — invaluable for debugging module resolution and class loading issues.

Skills & AGENTS.md Standards (BL-2415)

BoxLang now ships with AI agent skills in .agents/skills/ and updated AGENTS.md standards, providing structured domain knowledge for AI coding assistants working with BoxLang codebases.

ON_DATASOURCE_INITIALIZED Interception Point (BL-2454)

A new interception point fires after a datasource config is loaded but before the connection pool is established — giving modules full access to the raw HikariCP configuration for advanced customization:

MiniServer Health Metrics (BL-2455, BL-2456)

The MiniServer /health endpoint now includes Undertow worker pool statistics, WebSocket session counts, and additional JVM metrics. The MiniServer also supports static retrieval of the Undertow server instance and XNIO worker for programmatic metrics access.

🔧 Improvements

Language & Runtime

  • BL-1012BooleanFormat and TrueFalseFormat consolidated: TrueFalseFormat is now a deprecated alias for BooleanFormat, scheduled for removal in 2.0.

  • BL-2379 / BL-2450 — Function argument names now blocked from overlapping with import names; validation extended to closure/lambda argument names that shadow imports.

  • BL-2432 — Java interop varargs improved: BoxLang arrays passed to Java varargs methods no longer require manual unpacking into Object[].

  • BL-2436 — Auto-generate Java method stubs when a BoxLang class extends a Java class, filling in required abstract/interface method implementations.

  • BL-2437 — Support import aliases in extends and implements clauses for Java classes:

  • BL-2459 — Range type improvements with better element category detection (NUMBER, STRING, CHARACTER, IRANGEABLE, OTHER), enabling faster coercion and broader type support for range operations.

  • BL-2471 — Application objects now expose .getWatchers(), .getSchedulers(), and .getAppDuration() for runtime introspection of active watchers, registered schedulers, and application uptime.

CFML Compatibility & Transpiler

  • BL-2395 — CF compat: form.getPartsArray() added for compatibility with Adobe CF's form part enumeration.

  • BL-2397 / BL-2399 — CF transpiler CLI now supports config loading (by convention or explicit path) and new CLI flags for fine-tuned transpilation control.

  • BL-2410FileUpload now supports mimeType as an alias for the accept attribute:

  • BL-2460 — Transpile parameterExists() to isDefined() and quote the parameter name for correct resolution.

  • BL-2467 — Transpile hash( string='test' ) to hash( input='test' ) — the string argument is renamed to input to match BoxLang's hash() BIF signature.

Formatter

  • BL-2397 — Pretty print config can now be loaded by convention for the CF transpiler CLI tool.

  • BL-2442 — New template.enabled flag (defaults to false) gates experimental template formatting.

  • BL-2443 — New class.property_spacing rule (defaults to 1) for consistent property declaration spacing.

  • BL-2462 — Semicolons now correctly emitted on required rules when preserve is false.

Caching & Data

  • BL-2472ICacheStats.toStruct() now includes cache hit/miss ratios that were previously missing from the stats output.

  • BL-2473 — The remove() method on cache providers no longer double-JSON-serializes when the result is already a JSON string.

  • BL-2482 — UUID values are now JSON-serialized as strings instead of objects, preventing downstream deserialization issues.

MiniServer & Web

  • BL-2469 — Whitespace management now enabled on text/plain content types, matching the behavior already present for text/html.

Query & JDBC

  • BL-2468fromPendingQuery and query announcements now include the execution context that was previously missing from the event data.

  • BL-2485 — Duplicate logic between arrayUnique() and listRemoveDuplicates() consolidated into a shared implementation for consistency and maintainability.

String & Case Utilities

  • BL-2478 — PascalCase and KebabCase BIFs updated with additional edge case handling. All case-conversion functions (snakeCase, pascalCase, kebabCase) now robustly handle camelCase, PascalCase, snake_case, kebab-case, space-separated, and mixed inputs:

🐛 Bug Fixes (By Area)

Language & Parser

  • BL-2424 — Required function argument with no type no longer parsed as being of type "required" under certain conditions.

  • BL-2425 — Large if/else blocks no longer throw LargeMethodErrors — the compiler now splits oversized conditional blocks.

  • BL-2426 — Current template now correctly reported in an include from inside a function inside a class.

  • BL-2429 — Tag-based functions with output=true now correctly interpolate variables during parsing.

  • BL-2430 — CF transpiler no longer adds output=true to functions that don't match CF's default behavior.

  • BL-2445 — Interfaces with methods that lack default no longer have the default modifier incorrectly added, which broke interface contracts.

  • BL-2452 — Parser now correctly handles method chaining to expression invocation patterns.

  • BL-2470 — Unscoped internal call to a generated accessor setter no longer mis-resolves to a BIF (regression in 1.14.0-snapshot+4460).

  • BL-2475try/catch now works correctly within static blocks.

CFML Compatibility

  • BL-2331DateFormat no longer throws "Can't cast Number to a DateTime" on valid numeric date representations.

  • BL-2392 — Cached query metadata no longer mutated by subsequent cache retrievals — a defensive copy is returned.

  • BL-2405 — CF's query column passed to array now applies to bracket notation correctly.

  • BL-2406 — Template switch cases no longer incorrectly use break statements — alignment with CF semantics.

  • BL-2419ParseDateTime now supports yymmdd format parsing.

  • BL-2435 — CF compat: arrayMax(), arrayMin(), and arraySum() now accept dates in addition to numbers.

  • BL-2414 — Adobe CF compatibility: empty form fields removed from form scope list of same-named fields.

Formatter

  • BL-2441 — Formatter no longer adds double assignment expressions when using the include keyword.

  • BL-2444 — Empty blocks with comments no longer collapse into invalid code.

  • BL-2447 — Formatter now adds a line break when an expression is followed by HTML.

  • BL-2448 — Include issue fixed where formatter was adding an extra attribute that broke other engines.

  • BL-2462 — Semicolons now correctly emitted on required rules when preserve is false.

Query & JDBC

  • BL-2411 — JDBC trailing semicolon removal now handles multiple semicolons (not just one).

  • BL-2412 — QoQ single column in parentheses now takes the column name instead of defaulting to column_0.

  • BL-2413 — Improved thread safety of large QoQ operations under contention.

  • BL-2420 — Data validation now enforced when setting values into query objects.

  • BL-2421 — QoQ math operations no longer fail on string data — values are coerced automatically.

  • BL-2464 — Query timeout bug fixed — was using the wrong configuration key internally.

Web & HTTP

  • BL-2416 — WebService creation/usage now promotes HTTP/SSL exception messages to the main error message for better debuggability.

  • BL-2423 — OData POST requests fixed: a Content-Length: 0 header is now sent to resolve "411 Length Required" errors.

  • BL-2427enableOutputOnly setting now correctly uses output components from the parent context.

  • BL-2480writeToBrowser no longer overrides existing Content-Disposition header.

  • BL-2483 — Fixed URISyntaxException when executing files from paths containing spaces.

Caching, Serialization & Runtime

  • BL-2042LoggingService concurrent modification exception fixed with thread-safe logger management.

  • BL-2400 — Regression fix: serializeJSON() no longer stack overflows (1.13 regression).

  • BL-2402fileSetLastModified() now accepts a numeric timestamp in addition to date objects.

  • BL-2403Decrypt BIF now correctly decrypts complex/structured objects — previously corrupted nested data.

  • BL-2407 — Scheduler task methods using (Double period, String timeUnit) now handle plural time units correctly.

  • BL-2434dataNavigate now honors the default value parameter; a new getOrDefault() method provides explicit fallback behavior.

  • BL-2438 — Preserve primitive type case (e.g., int vs Int) in @overrideJava fallback stubs.

  • BL-2458 — Jackson JR JSON parsing no longer silently ignores trailing content — raises a parse error instead.

  • BL-2461 — Return values from interface methods are now properly coerced to the declared return type.

  • BL-2479BoxCacheStats.hitRate() no longer always returns 0 due to integer division — now uses floating-point arithmetic.

  • BL-2483 — Fixed URISyntaxException when executing files from paths containing spaces.

Scheduler & Async

  • BL-2407ScheduledTask methods using (period, timeUnit) with plural time units (e.g., "hours", "minutes") now work correctly — previously only singular forms were recognized.

String BIFs

  • BL-1007SnakeCase BIF now correctly converts from camelCase to snake_case instead of simply replacing spaces. All case-conversion BIFs (snakeCase, pascalCase, kebabCase) handle camelCase, PascalCase, snake_case, kebab-case, and space-separated inputs.

📊 Release Snapshot

  • Release Date: June 3, 2026

  • Total Issues: 65

  • Distribution: 24 New Features, 20 Improvements, 21 Bugs

  • Primary Focus: Language evolution (sets, inner classes, template classes) and developer experience (formatter, data navigation, REPL)

Last updated

Was this helpful?