Happy New Year! The BoxLang team is excited to announce BoxLang 1.9.0, a significant stability and compatibility release focused on production-readiness thanks to our client migrations and new application deployments. This release also introduces array-based form field parsing conventions, enhanced datasource lifecycle management, improved context handling, and resolves over 50 critical bugs to ensure enterprise-grade reliability for mission-critical applications.
🚀 What's New in 1.9.0
You can find the full engineering what's new guide here: https://boxlang.ortusbooks.com/readme/release-history/1.9.0
📦 Array-Based Form Field Parsing - Modern Web Conventions
BoxLang now automatically parses query parameters and form fields as arrays using modern naming conventions—no more manual listToArray() conversions:
// HTML form with multiple selections
<form method="POST">
<input type="checkbox" name="colors[]" value="red" />
<input type="checkbox" name="colors[]" value="blue" />
<input type="checkbox" name="colors[]" value="green" />
<button type="submit">Submit</button>
</form>
// BoxLang automatically parses as array
selectedColors = form.colors;
// Result: ["red", "blue", "green"]
// Works with query parameters too
// URL: /page?tags[]=boxlang&tags[]=java&tags[]=modern
tags = url.tags;
// Result: ["boxlang", "java", "modern"]
// Traditional single values still work
name = form.name; // Single string value
Benefits:
- ✨ No manual conversions needed
- 🎯 Consistent with modern web frameworks
- 🔄 Fully backward compatible
- 📡 Works with both POST and GET data
🔄 Enhanced Context Lifecycle Management - Proper Cleanup
Significant improvements to context management and shutdown handling ensure proper resource cleanup and prevent memory leaks in long-running applications:
Key Improvements:
- Thread Counter Tracking - Contexts maintain active thread counts for proper cleanup
- Exchange Detachment - Web contexts can detach during shutdown while still in use
- ORM Cleanup - ORM context removal moved to shutdown listeners
- Session Error Recovery - Errors in
onSessionEndno longer permanently break sessions - Startup Prevention - Sessions won't inadvertently start during app initialization
🗄️ Datasource Lifecycle Management - No More Connection Leaks
Critical fixes to datasource lifecycle prevent connection pool leaks and resource exhaustion:
class {
this.name = "MyApp";
this.datasources = {
"mydb" : {
driver : "mysql",
host : "localhost",
database : "appdb",
username : "user",
password : "pass"
}
};
function onApplicationEnd() {
// Datasources properly shutdown automatically
// No more connection pool leaks across application restarts!
writeLog( "Datasources cleaned up automatically" );
}
}
Fixed Issues:
- ✅ Application-level datasources shut down when application ends
- ✅ Server-level datasources no longer create duplicate pools per application
- ✅ Application caches properly removed on application end
- ✅ Connection pool cleanup during entire application lifecycle
📊 Comprehensive Query and JDBC Enhancements
Major improvements to query handling and database operations across all drivers:
Oracle Database Improvements:
// Named parameters now work correctly
queryExecute(
"SELECT * FROM users WHERE id = :userId AND status = :status",
{
userId : { value : 123, type : "integer" },
status : { value : "active", type : "varchar" }
},
{ datasource : "oracle_ds" }
);
// Ref cursor parameters work regardless of position
bx:storedproc procedure="getUserData" datasource="oracle_ds" {
bx:procparam type="in" value=123 cfsqltype="cf_sql_integer";
bx:procparam type="out" variable="result" cfsqltype="cf_sql_refcursor";
}
// Unused procresult tags properly ignored (no errors)
bx:storedproc procedure="processData" datasource="oracle_ds" {
bx:procresult name="unused"; // Safe even if not returned
bx:procparam type="in" value="data";
}
Parameter Handling:
// Empty lists in queryparam handled correctly (CFML compat)
bx:query name="filtered" {
writeOutput( "
SELECT * FROM products
WHERE category IN (
<bx:queryparam value='#categoryList#' list='true' />
)
" );
}
// Integer SQL type now properly validates instead of truncating
queryExecute(
"INSERT INTO scores (value) VALUES (?)",
[ { value : 95.5, type : "integer" } ] // Now throws error (was silently truncating)
);
Query of Queries:
// NULL comparisons with LIKE now work correctly
query1 = queryNew( "name,description", "varchar,varchar", [
[ "Product 1", null ],
[ "Product 2", "A great product" ]
] );
result = queryExecute(
"SELECT * FROM query1 WHERE description LIKE '%product%'",
{},
{ dbtype : "query" }
);
// Properly handles NULL values without errors
🔢 Number Handling Improvements - Clean Serialization
Significant enhancements to numeric type handling prevent scientific notation in JSON:
// Doubles serialize without scientific notation
bigNumber = 1234567890.123456;
jsonStr = jsonSerialize( { value : bigNumber } );
// Output: {"value":1234567890.123456}
// NOT: {"value":1.234567890123456E9}
// BigDecimals also serialize cleanly
amount = preciseValue( "999999999.99" );
jsonStr = jsonSerialize( { amount : amount } );
// Output: {"amount":999999999.99}
// Scientific notation literals with leading zeros parse correctly
value = 0001.5e2; // Now works: 150
// String-to-double conversion trims whitespace
value = toNumeric( " 42.5 " ); // Now works: 42.5
🎭 Enhanced Class Metadata - Static and Abstract Flags
Class metadata now includes static and abstract flags for functions:
abstract class {
static function getVersion() {
return "1.9.0";
}
abstract function process();
}
// Inspect metadata
meta = getMetadata( MyClass );
functionMeta = meta.functions[ "getVersion" ];
println( "Is static: #functionMeta.static#" ); // true
println( "Is abstract: #functionMeta.abstract#" ); // false
// Use in reflection scenarios
if( functionMeta.static ) {
version = invoke( MyClass, "getVersion" );
}
Additional Metadata Improvements:
- Component metadata returns struct for
implements(not string) - Interface metadata properly structured
- Doc comments preserve line breaks
- Doc comments inside script blocks associate properly
🧹 SOAP Client Improvements
The SOAP client from 1.8.0 enhanced with proper class structure:
// SOAP client now has full class capabilities
ws = soap( "http://example.com/service.wsdl" );
// Access underlying HTTP methods
ws.setTimeout( 60 );
ws.setHeader( "Authorization", "Bearer token123" );
// Invoke SOAP methods with improved reliability
result = ws.invoke( "getUserInfo", 123 );
println( "User: #result.name#" );
📝 Mid() Function Enhancement
The mid() BIF now has optional count parameter for flexible string extraction:
// Extract from position to end of string
text = "Hello World";
result = mid( text, 5 ); // "o World"
// Extract with count (existing behavior)
result = mid( text, 5, 3 ); // "o W"
// More intuitive substring operations
greeting = "Good Morning Everyone";
timeOfDay = mid( greeting, 6, 7 ); // "Morning"
remainder = mid( greeting, 14 ); // "Everyone"
🐛 50+ Critical Bug Fixes
CFML Compatibility (15+ fixes)
- ListDeleteAt - Retains leading delimiters (proper CFML behavior)
- ListAppend - Behavior matches CFML exactly
- Boolean Strings - Characters 'y' and 'n' recognized as booleans in compat mode
- Session IDs - Properly prefixed with app identifier when J2EE sessions enabled
- GetComponentMetaData - Returns struct for
implements(not string) - Empty Query Params - Empty lists in cfqueryparam handled correctly
- CreateUUID - Returns standard UUID format
File Operations (5+ fixes)
- File Upload -
resultfield properly populated after upload - Content Types - Upload
contentTypeno longer includescontentSubType - File Append -
action="append"correctly appends with line breaks
Date & Time (5+ fixes)
- DateTime Parsing - Fixed casting with formats like "Dec/13/2025 08:00"
- DateAdd -
datepartparameter no longer case-sensitive - GetHTTPTimeString - Always returns GMT timezone
Session and Cookie (5+ fixes)
- Session End Errors - Errors no longer leave session permanently expired
- Session Prevention - Sessions don't start during app initialization
- Cookie Serialization - Time serialized in GMT as expected
Core Runtime (10+ fixes)
- Duplicate - Properly handles recursive references
- ExpandPath - Works correctly outside request context (in
onServerStart) - For Loops - Work properly with Java primitive arrays
- Evaluate - Uses CF transpiler when called from CF source
- Whitespace - Preserve whitespace no longer consumes excessive line breaks
- Class Loading - Fixed race conditions with concurrent class loading
Database and ORM (5+ fixes)
- Redis Query Caching - Fixed serialization with cached queries
- ORM Datasources - ORM properly finds datasources without errors
- Stored Procedure Return Codes - Use correct key names
Memory and Threading (5+ fixes)
- Stream Handling - Fixed "Stream is closed" errors (UT010029)
- Context Threading - Proper handling with multiple active threads
- Comparison Sorting - Fixed "Comparison method violates its general contract"
String Operations (5+ fixes)
- ReReplace - Fixed index out of bounds errors
- String Comparison - Better error handling in comparisons
- Class Inspection - Improved error handling for complex object dumps
🔧 Configuration Updates
HTTP Multipart Simplification
File uploads no longer require explicit multipart() call in many cases:
// Automatic multipart detection
http( "https://api.example.com/upload" )
.post()
.file( "document", "/path/to/file.pdf" )
.send();
// multipart() automatically applied when files present
Transaction Component Cleanup
Removed unused nested attribute from transaction component:
// Simplified transaction syntax
transaction {
queryExecute( "INSERT INTO users (name) VALUES (?)", [ "John" ] );
queryExecute( "INSERT INTO logs (action) VALUES (?)", [ "user_created" ] );
}
// Nested transactions work automatically
transaction {
queryExecute( "UPDATE accounts SET balance = balance - 100 WHERE id = 1" );
transaction {
queryExecute( "UPDATE accounts SET balance = balance + 100 WHERE id = 2" );
}
}
📡 MiniServer JSON Configuration
MiniServer configuration via JSON files (introduced in 1.8.0) is now finalized:
# Automatically loads miniserver.json
boxlang-miniserver
# Or specify custom config
boxlang-miniserver /path/to/config.json
Example Configuration:
{
"port" : 8080,
"webRoot" : "./www",
"debug" : true,
"rewrites" : true,
"rewriteFileName" : "index.bx",
"healthCheck" : true
}
🎯 Why This Release Matters
BoxLang 1.9.0 represents our continued commitment to production-grade reliability. The focus on lifecycle management, datasource cleanup, and CFML compatibility makes this release essential for:
- Enterprise Applications - Running mission-critical workloads with confidence
- CFML Migrations - Smoother transitions with enhanced compatibility
- Long-Running Services - Proper resource cleanup prevents memory leaks
- High-Volume Applications - Optimized connection pooling and cache management
Download
Please visit our download page or our quick installation guides to upgrade your installation.
Professional Open Source
BoxLang is a professional open-source product, with three different licences:
- Open-Source Apache2
- BoxLang +
- BoxLang ++
BoxLang is free, open-source software under the Apache 2.0 license. We encourage and support community contributions. BoxLang+ and BoxLang ++ are commercial versions offering support and enterprise features. Our licensing model is based on fairness and the golden rule: Do to others as you want them to do to you. No hidden pricing or pricing on cores, RAM, SaaS, multi-domain or ridiculous ways to get your money. Transparent and fair.
BoxLang is more than just a language; it's a movement.
Join us and redefine development on the JVM Ready to learn more? Explore BoxLang's Features, Documentation, and Community.
Add Your Comment