Page cover

1.0.0-RC.3

April 3, 2025

We are so excited to release RC.3 for BoxLang. We have squashed almost 100 tickets for this release. Making it the most performant and solid release to date. We do not have any more release candidates scheduled, so this might be the last before our final release on May 1st. So please, please test your applications and report any issues.

Below, you can find some of the significant accomplishments of this release and the full release notes.

Performance

We have tested the runtime against all our major libraries, ColdBox, TestBox, and ContentBox, and included our major ColdBox modules. BoxLang now officially runs all of our test suites faster than Adobe 2021, 2023, and 2025, with a give-or-take with the Lucee CFML engine.

BXORM

We have now released our bx-orm module, which gives you full integration with JPA/Hibernate into your BoxLang applications. The documentation site is coming soon at bxorm.ortusbooks.com

install-bx-module bx-orm

Virtual Threads

We have finalized our core executors in BoxLang and fully integrated Java Virtual threads so you can use them in your applications. The core executors in BoxLang now are:

"executors": {
	// Use this for IO bound tasks, does not support scheduling
	// This is also the default executor for parallel operations
	// This is also the default when requestion an executor service via executorGet()
	"io-tasks": {
		"type": "virtual"
	},
	// Use this for CPU bound tasks, supports scheduling
	"cpu-tasks": {
		"type": "scheduled",
		"threads": 10
	},
	// Used for all scheduled tasks in the runtime
	"scheduled-tasks": {
		"type": "scheduled",
		"threads": 10
	}
},

As you can see, we have 3 executors pre-defined for the runtime:

  • io-tasks- A virtual thread executor for high I/O intensive tasks

  • cpu-tasks- A scheduled executor with 10 base threads for your CPU-intensive tasks

  • scheduled-tasks- A dedicated executor with 10 base threads for scheduling

This now allows us to create Java-based virtual threads using BoxLang constructs threadNew()BIF or the threadcomponent:

threadNew( 
  runnable: () => {},
  virtual: true
)

bx:thread name="virtualTest" virtual=true{
  // A virtual thread.
}

The default for parallel executions in map(), filter(), each()have also been updated to leverage virtual threads by default. You can use the virtual = falseso they can execute in the cpu-tasksexecutor if needed. Enjoy the power of virtual threads.

Schedulers

We now can do schedulers in pure BoxLang. This allows us to integrate it into every corner of the runtime. All the docs for scheduling are coming. Here is a sneak peek of a pure BoxLang scheduler:

class {

	// Properties
	property name="scheduler";
	property name="runtime";
	property name="logger";
	property name="asyncService";
	property name="cacheService";
	property name="interceptorService";

	/**
	 * The configure method is called by the BoxLang runtime
	 * to allow the scheduler to configure itself.
	 *
	 * This is where you define your tasks and setup global configuration.
	 */
	function configure(){
		// Setup Scheduler Properties
		scheduler.setSchedulerName( "My-Scheduler" )
		scheduler.setTimezone( "UTC" )

		// Define a lambda task
		scheduler.task( "My test Task" )
			.call( () -> {
				println( "I am a lambda task: #now()#" );
			} )
			.every( 2, "second" );
	}

	/**
	 * --------------------------------------------------------------------------
	 * Life - Cycle Callbacks
	 * --------------------------------------------------------------------------
	 */

	/**
	 * Called after the scheduler has registered all schedules
	 */
	void function onStartup(){
		println( "I have started!" & scheduler.getSchedulerName() );
	}

	/**
	 * Called before the scheduler is going to be shutdown
	 */
	void function onShutdown(){
		println( "I have shutdown!" & scheduler.getSchedulerName() );
	}

	/**
	 * Called whenever ANY task fails
	 *
	 * @task      The task that got executed
	 * @exception The exception object
	 */
	function onAnyTaskError( task, exception ){
		println( "Any task [#task.getName()#]  blew up " & exception.getMessage() );
	}

	/**
	 * Called whenever ANY task succeeds
	 *
	 * @task   The task that got executed
	 * @result The result (if any) that the task produced as an Optional
	 */
	function onAnyTaskSuccess( task, result ){
		println( "on any task success [#task.getName()#]"  );
		println( "results for task are: " & result.orElse( "No result" ) );
	}

	/**
	 * Called before ANY task runs
	 *
	 * @task The task about to be executed
	 */
	function beforeAnyTask( task ){
		println( "before any task [#task.getName()#]"  );
	}

	/**
	 * Called after ANY task runs
	 *
	 * @task   The task that got executed
	 * @result The result (if any) that the task produced as an Optional
	 */
	function afterAnyTask( task, result ){
		println( "after any task completed [#task.getName()#]"  );
		println( "results for task are: " & result.orElse( "No result" ) );
	}

}

You can find the scheduler API Docs here: https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-rc.3/ortus/boxlang/runtime/async/tasks/BaseScheduler.html

CLI Scheduler

You can now run schedulers from the CLI in any operating system using our new boxlang schedulecommand. Just tell it which scheduler to spin up and forget about CRON.

boxlang schedule MyScheduler.bx

This will spawn our scheduled tasks, run your scheduler, and wait until you manually block it; if not, it runs forever.

Runtime Schedulers & Configuration

You can also now declare schedulers in your boxlang.jsonthat once the runtime starts, it will startup your schedulers.

"scheduler": {
    // The default scheduler for all scheduled tasks
    // Each scheduler can have a different executor if needed
    "executor": "scheduled-tasks",
    // The cache to leverage for server fixation or distribution
    "cacheName": "default",
    // An array of BoxLang Schedulers to register upon startup
    // Must be an absolute path to the scheduler file
    // You can use the ${user-dir} or ${boxlang-home} variables or any other environment variable
    // Example: "schedulers": [ "/path/to/Scheduler.bx" ]
    "schedulers": [],
    // You can also define tasks manually here
    // Every task is an object defined by a unique name
    // The task object is a struct with the following properties:
    // - `crontime:string` - The cron time to run the task (optional), defaults to empty string
    // - `eventhandler:path` - The absolute path to the task event handler(optional), defaults to empty string
    // - `exclude:any` - Comma-separated list of dates or date range (d1 to d2) on which to not execute the scheduled task
    // - `file:name` - Name of the log file to store output of the task (optional), defaults to `scheduler`
    // - `group:string` - The group name of the task (optional), defaults to empty string
    "tasks": {}
},

You can now also choose the default executor and cache to use for server fixations. The schedulersis an array of absolute paths to your scheduler bx classes to load.

Application.bx Schedulers

You can also define schedulers for your particular applications using the Application.bxfile and the this.schedulerssetting.

class{

    ...
    
    this.schedulers = [ "path.to.Scheduler" ]

}

As you can see, the value is an array of instantiation paths. At application startup, the schedulers will be created, registered, and started for you.

Scheduler BIFs

You also now have a collection of new BIFs to interact with your schedulers and even submit schedulers programmatically.

  • SchedulerStart( path, [force=false] ) - Create, register and start a new scheduler class.

  • SchedulerShutdown( name, [force=false], [timeout=0] ) - Shutdown a scheduler

  • SchedulerRestart( name, [force=false], [timeout=0] ) - Restart a scheduler

  • SchedulerStats( [name] ) - Get a strut of stats of one or all registered schedulers

  • SchedulerList() - Get an array of names of all schedulers

  • SchedulerGet( name ) - Get a scheduler instance by name

  • SchedulerGetAll() - Get all the registered schedulers

Release Notes

Improvements

BL-1262 Command to schedule Schedulers: boxlang schedule {path.bx}

BL-1265 Allows for an array of BoxLang schedulers to be loaded on the startup of the runtime

BL-1269 this.schedulers for Application.bx loading of schedulers

BL-1268 Scheduler BIFS for managing schedulers programmatically

BL-1264 configuration for `schedulers` in the `boxlang.json`

BL-1212 Add parser methods to report on and clear ANTLR cache

BL-1207 this.moduleDependencies for Modules so they can activate module dependencies

BL-1170 New convention boxlang_modules wherever you start a BoxLang app it loads those modules first

BL-1171 Added Liberica JDK as a supported version of our language

BL-1172 Add HttpVersion key to http component

BL-1176 add missing "hex" validation to isValid()

BL-1181 executorGet() with no params must return the default executor

BL-1182 Allow throw; with no expression

BL-1183 change listener improvements

BL-1193 Support @module-name suffix for class loading

BL-1195 missing bifs: BoxUnregisterInterceptor(), BoxUnregisterRequestInterceptor()

BL-1196 Added isVirtual, isDaemon, threadGroup, id to the thread metadata

BL-1197 Threading Improvements: isThreadAlive(), isThreadInterrupted(), threadInterrupt() bifs

BL-1206 modules directories being created unecesarrily if not found

BL-1208 enable transparent anchors in java regex

BL-1209 Ensure implicit onRequest() method allows output, even if output=false at the application level

BL-1239 Add Virtual Attribute to Thread Component

BL-1240 Solidify all the executors that ship with the runtime: io-tasks, cpu-tasks, and scheduled-tasks

BL-1251 Put debug mode cache clearing behind a config flag: clearClassFilesOnStartup

BL-1258 Make Java interop varargs optional

BL-1259 only populate form.fieldNames on POST method

BL-1260 Add `modules` key to server.boxlang struct

BL-1263 Add `BoxCache` annotation to allow aliasing cache providers

Bugs

BL-1023 When First Request to Application is a CFC, the application scope is undefined

BL-1083 cliRead adds a line break

BL-1107 Dump of XML Object Does not Include Node Names

BL-1145 When calling a remote Bx method, specifying returnformat in the pseudo-constructor does not work

BL-1154 ASM BoxPiler is setting up properties after pseudoconstructor runs instead of before

BL-1162 BoxLang BIF Proxy losing context of execution

BL-1163 Key instance not being coerced to string

BL-1164 Super Scope is Lost When UDF in child class from closure in parent class

BL-1165 Static method calling static method loses static context

BL-1166 application.applicationName is a Key instance, not a string

BL-1168 GetContextRoot Returning Slash-Prefixed Root

BL-1169 Strings which contain invalid octals are not casting correctly in the NumberCaster

BL-1174 access remote not recognised

BL-1175 Unable to compile/call box class with java override

BL-1177 `expandPath` not expanding mappings when used in the Application pseudo constructor

BL-1178 Compat: reMatchNoCase should find matches but generates error

BL-1179 expandPath() matches partial folders when mapping path doesn't have trailing slash

BL-1185 getMetata getClass().getSimpleName()|.getName() on IBoxRunnable returns Struct class names

BL-1187 NPE when passing null to first constructor arg of a box class

BL-1188 Space missing when cfquery in function

BL-1189 bx:zip doesn't implement result

BL-1191 Add support for `this.caches` in Application.bx|cfc

BL-1192 Can't create box class with literal @ symbol in name

BL-1198 CGI Scope should check variable name before attempting http_header_name convention

BL-1200 DynamicObject does not support dereference and invocation of non-static BoxLang class methods

BL-1201 Invoke BIF No Longer Functioning on Java Objects in Compat mode

BL-1202 java list dump template breaks in compat mode when expand is not passed

BL-1203 Java Interop - Typed Primitive Arrays passed as Java Args are always `Object[]`

BL-1204 Compiler error - Non-literal value in BoxExpr type with hash expression

BL-1205 ClassMetaDataVisitor cannot find super class in same directory

BL-1210 cfhttp port attribute is not supported

BL-1211 servlet runtime using wrong getPageContext() BIF

BL-1213 Error accessing Map<String,Object> when the key doesn't exist

BL-1215 directoryList has odd behavior when using 'dot' paths

BL-1220 Java Interop - StringBuilder usage is incorrectly passed through to String `replace` BIF

BL-1221 Error in cfdump when dumping a xml variable

BL-1222 Array Index Assignment for appending XML Children Not Working

BL-1223 class java.lang.Integer cannot be cast to class java.lang.String

BL-1224 Error serializing to JSON

BL-1225 getPageContext Lucee compatibility

BL-1226 DateConvert BIF Not Locale Aware

BL-1227 cftransaction - Failed to set savepoint

BL-1228 Can't cast [] to a DateTime

BL-1229 Illegal class name

BL-1230 ListToArray on a Null value Throws Exception

BL-1231 ReplaceNoCase with Integer Replacement throws Exception

BL-1232 Compat - can't cast Short month with time to date

BL-1233 Java Interop - Explicit java.time.Duration is cast to BigDecimal upon use

BL-1234 current template not set in static initializer block

BL-1236 apparent connection leak detected

BL-1237 Issue with Java interop and var args

BL-1238 Array element type mismatch when using primitive arrays of non-well-known classes

BL-1241 Modify dump when dumping a class instance

BL-1242 Default cache was not being defaulted

BL-1243 Default cache should only allow properties to be overriden, not type

BL-1244 system cache clear now can clear query caching

BL-1245 Cache Component Not Accepting Timespan Timeout and IdleTime Args Correctly

BL-1246 Replace BIF fails when replacement argument is numeric

BL-1247 cfcatch key detail is missing

BL-1248 Can't cast [Tue Nov 22 11:01:51 CET 2022] to a DateTime

BL-1249 class java.lang.Integer cannot be cast to class java.lang.String

BL-1250 Invoke Throws Error When Null Value is Assigned on Generated Setter

BL-1252 Consider renaming jsonDeserialize member function

BL-1255 JDBC - SQL Server Error When Using Date Time in Query Param

BL-1256 Incorrect parsing of string times when used in time format when Zone is different from system

BL-1257 Unsupported isolation level: READ_COMMITTED

BL-1261 Miniserver getPageContext().getResponse().reset() not clearing status code and headers

Last updated

Was this helpful?