All pages
Powered by GitBook
1 of 46

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Release History

All the major information about BoxLang Releases

Versioning Schema

BoxLang is maintained under the Semantic Versioning guidelines as much as possible. Releases will be numbered in the following format:

And constructed with the following guidelines:

  • Breaking backward compatibility bumps the major (and resets the minor and patch)

  • New additions without breaking backward compatibility bump the minor (and resets the patch)

  • Bug fixes and misc changes bump the patch

BoxLang Release & Support Lifecycle

Our release cadence follows a predictable yearly major-version schedule, with each release enjoying two years of Long-Term Support (LTS):

  • Active Support: First 12 months after release – full feature updates, bug fixes & security patches.

  • LTS (Updates & Security): 2nd year – maintenance releases (minor improvements & security).

  • LTS (Security-Only): 3rd year – critical security fixes only, then archived.

This gives you a clear planning horizon and overlap between versions, so you can upgrade on your own schedule without ever being left unprotected.

Support Lifecycle Chart

Here is our 5-year outlook.

Version
Active Support
LTS (updates & security)
LTS (security-only)
  • After the “security-only” phase, the version is archived: no further updates, but archives remain available for reference.

  • Overlaps ensure there’s always at least one actively maintained release.

  • All dates refer to calendar years; exact dates will align with our annual major-version launch each Q1.

Contributing Guide

The best way to contribute to BoxLang!

Hola amigo! I'm excited that you are interested in contributing to BoxLang. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:

Code Of Conduct

This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be useful to other developers and/or businesses. Your contributions are crucial in maintaining the integrity of BoxLang. Be considerate towards maintainers when raising issues or presenting pull requests. We all follow the Golden Rule: Do to others as you want them to do to you.

  • As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

  • Participants will be tolerant of opposing views.

  • Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

  • Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions not aligned with this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

  • When interpreting the words and actions of others, participants should always assume good intentions. Emotions cannot be derived from textual representations.

  • Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more project maintainers.

Bug Reporting

Please link it to the appropriate issue if you submit a pull request.

If you file a bug report, your issue should contain a title, a clear description of the issue, a way to replicate the issue, and any support files we might need to replicate your issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix for it. Not all issues that do not contain a way to replicate will be addressed.

Support Questions

If you have questions about usage, professional support, or ideas to bounce off the maintainers, please do not create an issue. Leverage our support channels first.

  • Ortus Community Discourse:

  • Box Slack Team:

  • Professional Support:

Pull Request Guidelines

  • The main branch is just a snapshot of the latest stable release. All development should be done in dedicated branches. Do not submit PRs against the main branch. They will be closed.

  • All pull requests should be sent against the development branch or the LTS version branch releases/v{version}

  • It's OK to have multiple small commits as you work on the PR - GitHub will automatically squash it before merging.

Security Vulnerabilities

If you discover a security vulnerability, please email the development team at . All security vulnerabilities will be promptly addressed.

JRE Compatibility

Please make sure your code runs on JRE 21+

Financial Contributions

You can support BoxLang and all of our Open Source initiatives at Ortus Solutions by becoming a Patreon. You can also get lots of goodies and services depending on the level of contributions.

<major>.<minor>.<patch>
  • Make sure all local tests pass before submitting the merge.

  • Please make sure all your pull requests have companion tests.

  • Please link the Jira issue in your PR title when sending the final PR

  • https://ortussolutions.atlassian.net/browse/BL
    https://community.ortussolutions.com
    https://boxteam.ortussolutions.com
    https://www.ortussolutions.com/services/support
    [email protected]
    Become a backer or sponsor on Patreon
    One-time donations via PayPal

    2029 – 2030

    v4

    2028 – 2029

    2029 – 2030

    2030 – 2031

    v5

    2029 – 2030

    2030 – 2031

    2031 – 2032

    v1

    2025 – 2026

    2026 – 2027

    2027 – 2028

    v2

    2026 – 2027

    2027 – 2028

    2028 – 2029

    v3

    2027 – 2028

    2028 – 2029

    Introduction

    Welcome to BoxLang: A Modern Dynamic JVM Language

    BoxLang is a modern dynamic JVM language that can be deployed on multiple runtimes: operating system (Windows/Mac/*nix/Embedded), web server, lambda, iOS, android, web assembly, and more. BoxLang combines many features from different programming languages, including Java, CFML, Python, Ruby, Go, and PHP, to provide developers with a modern, functional and expressive syntax.

    BoxLang Multi-Runtime

    BoxLang has been designed to be a highly adaptable and dynamic language to take advantage of all the modern features of the JVM and was designed with several goals in mind:

    1. Be a rapid application development (RAD) scripting language and middleware.

    2. Unstagnate the dynamic language ecosystem in Java.

    3. Be dynamic, modular, lightweight, and fast.

    4. Be 100% interoperable with Java.

    5. Be modern, functional, and fluent (Think mixing CFML, Node, Kotlin, Java, and Clojure)

    6. Extend via Modules

    7. Be able to support multiple runtime environments:

      1. Native OS Binaries (CLI Tooling, compilers, etc.)

      2. Serverless Computing (AWS Lambda, Azure Functions, etc)

      3. Servlet Containers - CommandBox/Tomcat/Jetty/JBoss/Undertow

    8. Compile down to Java ByteCode

    9. Framework Capabilities (Scheduling, applications, events, async computing, tasks, queues, modules)

    10. Drop-in Replacement for Adobe ColdFusion and Lucee CFML

    BoxLang can also be used as a drop-in replacement for Adobe ColdFusion or Lucee CFML Engines by leveraging our bx-compat-cfmlmodule. NO CODE CHANGES, FASTER, MODERN AND SAVE MONEY.

    Launch Video

    License

    BoxLang is open source and licensed under the License. Copyright and Registered Trademark by Ortus Solutions, Corp.

    BoxLang Subscriptions

    BoxLang can also be enhanced by to give you:

    • Business Support with SLAs

    • Enhanced builds

    • Custom patches and builds

    • Dedicated Engineer

    Support Open Source

    To support us, please consider becoming our patron at for as little as $10/month.

    Discussions & Help

    The Ortus Community is how to get help:

    You can also join our Slack Box Team at:

    Reporting a Bug

    We all make mistakes from time to time :) So why not let us know about it and help us out? We also love 😍 pull requests, so please star us and fork us at

    Jira Issue Tracking

    • BoxLang:

    • BoxLang IDE:

    • BoxLang Modules:

    Resources

    • Professional Support:

    • GitHub Org:

    • Twitter:

    • FaceBook:

    Ortus Solutions, Corp

    This book was written and maintained by and the Development Team.

    Ortus Solutions is a company that focuses on building professional open source tools, custom applications and great websites! We're the team behind ColdBox, the de-facto enterprise BoxLang HMVC Platform, TestBox, the BoxLang Testing and Behavior Driven Development (BDD) Framework, ContentBox, a highly modular and scalable Content Management System, CommandBox, the BoxLang <BoxLang> CLI, package manager, etc, and many more -

    Beta Stage

    This is the collection of Betas we released since our first version.

    RC Stage

    This is the collection of Release Candidates we released since our first version.

    Docker Containers

  • Android/iOS Devices

  • Web assembly

  • Etc

  • Premium Modules
  • Much More...

  • LinkedIn: https://www.linkedin.com/company/tryboxlang

    Professional Open-Source Support
    Overview
    Apache 2
    purchasing subscriptions
    patreon.com/ortussolutions
    https://community.ortussolutions.com/c/boxlang/42
    https://boxteam.ortussolutions.com
    https://github.com/ortus-boxlang/boxlang
    https://ortussolutions.atlassian.net/browse/BL
    https://ortussolutions.atlassian.net/browse/BLIDE
    https://ortussolutions.atlassian.net/browse/BLMODULES
    https://www.ortussolutions.com/services/support
    https://github.com/ortus-boxlang
    https://x.com/TryBoxLang
    https://www.facebook.com/tryboxlang/
    Luis Majano
    Ortus Solutions
    https://www.ortussolutions.com/

    1.0.0-Beta17

    October 4th, 2024

    In this release, we've introduced the exciting addition of websockets support to BoxLang through the powerful SocketBox module. This enhancement is not limited to our CommandBox Runtime but also extends to our MiniServer runtime, creating a more dynamic and efficient framework for real-time communication. For an in-depth introduction to these features, please visit our community post here.

    Additionally, we've implemented several new features and improvements. We've also improved the system startup process by adding version and build date information to the MiniServer startup output (BL-607). Lastly, we've addressed session management by ensuring that application settings are readily accessible during the onSessionEnd event (BL-610). This release encapsulates our ongoing commitment to providing robust, cutting-edge solutions for developers and reaching stable release in the coming weeks.

    New Features

    MiniServer WebSocket handler

    Improvement

    Add version/build date to output of Miniserver startup

    onSessionEnd needs application settings made available

    Remove debugmode capture on miniserver, delegate to the core runtime.

    Bugs

    Timeouts (connection, idle) for datasources needs to be in seconds and not in milliseconds to adhere to cfconfig

    BoxLang resolvers do not allow class paths to have `-` in them.

    1.0.0-Beta 4

    BoxLang Betas are released weekly. This is our fourth beta marker. Here are the release notes.

    Beta 4 is a small incremental release which includes improvements and bug fixes.

    Improvements

    BL-299, BL-300, BL-301, BL-302 Query caching improvements and compatibility updates

    BL-315 Ensure request attributes are available to the web runtime scope

    BL-164 bx-compat-cfml CFML compatibility module updates to ensure null query column values are returned as empty strings

    Bug Fixes

    Fixes compilation issue with variables name cfcatch

    CFML compatiblity for CGI.QUERY_STRING when not provided

    Fix null queryparam functionality

    About This Book

    Learn more about this book

    The source code for this book is hosted on GitHub: . You can freely contribute to it and submit pull requests. Ortus Solutions, Corp copyrights the contents of this book and cannot be altered or reproduced without the author's consent. All content is provided "As-Is" and can be freely distributed.‌

    Notice of Liability

    ‌The information in this book is distributed as is, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity concerning loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software, and resources described in it.

    1.0.1

    May 1, 2025

    Bugs

    BoxRunner fails on some input args

    BL-605
    BL-607
    BL-610
    BL-611
    BL-608
    BL-609
    BL-305
    BL-309
    BL-314
    BL-1353
    Charitable Proceeds‌

    10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - https://www.harvesting.org/. So please donate and purchase the printed version of this book; every book sold can help a child for almost two months.‌

    Shalom Children's Home

    Shalom Children's Party!

    The Shalom Children's Home (https://www.harvesting.org/) is one of the ministries that are dear to our hearts located in El Salvador. During the 12-year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

    Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education, and life skills training in a Christian environment. A child sponsorship program supports the home.‌

    We have supported Shalom since 2010; it is a place of blessings for many children in El Salvador who either have no families or have been abandoned. This is a good earth to seed and plant.

    https://github.com/ortus-boxlang/boxlang-docs

    1.0.0-Beta18

    This release introduces several new features and configurations to enhance functionality and security. It also continues to squash tons of bugs to bring about CFML compatibility. Key updates include:

    • Enhanced arrayFind and arrayFindNoCase functions, allowing value closures to accept item indices.

    • New validBoxLangTemplates configuration for filtering templates processable by the Runnable Loader.

    • New validClassExtensions configuration to specify permissible class extensions.

    • A new security configuration section designed to disallow BIFs, Components, and Imports, enhancing security.

    New Feature

    arrayFind, arrayFindNoCase value closures, accept the value and now the index of the item as the second param

    New configuration: validBoxLangTemplates to determine which templates the Runnable Loader can process

    New configuration: validClassExtensions to determine which class extensions to work with

    New security configuration section for disallowing: BIFS, Components, Imports

    Internal refactor to make the class locator and resolvers have a life-cycle based on the runtime and not alone

    Improvement

    Remove debugmode capture on miniserver, delegate to the core runtime.

    Consolidate CastAttempt and Attempt into a hierarchy

    New DynamicFunction type that can be used to generate dynamic BoxLang functions using Java Lambda proxies. Great for code generation

    Bug

    Import nested classes

    Java static funcitons not behaving as expected

    array.find does not use cf rules to convert result of predicate to boolean

    QueryColumnType doesn't handle "idstamp" (mssql)

    static scope in application.cfc not initialized before psuedoConstructor runs

    Auto-escaping of {} in regex needs to ignore already-escaped braces

    Instead of removing special chars from Java FQN, replace with __ to avoid conflicts

    Tag expressions not parsing inside template island inside braces

    duplicate() doesn't work on empty structs

    randrange() not inclusive of upper bound

    array.find - can't cast closure to string

    1.0.0-Beta21

    October 25th, 2024

    This release brings another round of powerful tools and refinements to the BoxLang community, making development more dynamic and robust than ever. We’ve added new capabilities for debugging and tracing, expanded context-sensitive controls for thread management, and introduced new methods for fluent attachment handling.

    For deeper flexibility, our improvements enhance configurability, streamline session control, and add deeper levels of JSON serialization management. Plus, we’ve squashed a wide range of bugs, enhancing stability across database connections, date handling, and runtime compatibility with CFML.

    In addition, CSRF Token functionality is now provided via the bx-csrf module.

    New Feature

    BL-713 Global events for Application events

    Implement table filter for dbinfo component

    getComponentList() should also return the declared attributes of a component

    getFunctionList() should also return the declared arguments of a BIF

    Improvement

    Implement Algorithm Argument for RandRange

    Set request class loader into thread as context class loader

    Retain directories in dynamic class loader

    Add nullIsUndefined flag to control how null variables are handled

    Don't default properties with no default value to null when compat has enabled nullIsUndefined scope behavior

    Bug

    Passing a null named argument hides outer bindings by the same name

    Missing BIF - CSRFGenerateToken is now supplied with the bx-csrf module

    Difference in args vs local variables handling

    Incompat: metadata annotations from inherited sub classses added to top level class

    cfloop collection with an array throws casting exception

    argument collection optional param is null

    dot access not chaining to static access

    NPE when calling non-existent Java method

    Duplicate of cfc instance presenting as struct

    Key access in StructMapWrapper not working

    GetTagData(), GetFunctionData() function not implemented, implement in the COMPAT module

    import name restrictions too strict

    Assignment not working on static fields of an imported class

    Adding two ints uneccessarily returns a long

    1.1.0

    May 12, 2025

    New Features

    • BL-1365 Add parse() helper methods directly to runtime, which returns parse result

    • BL-1388 new security configuration item: populateServerSystemScope that can allow or not the population of the server.system scope or not

    Improvements

    • Create links to BoxLang modules

    • match getHTTPTimeString() and default time to now

    • Work harder to return partial AST on invalid parse

    • Error executing dump template [/dump/html/BoxClass.bxm]

    Bugs

    • BoxLang date time not accepted by JDBC as a date object

    • contracting path doesn't work if casing of mapping doesn't match casing of abs path

    • sessionInvalidate() "Cannot invoke String.length() because "s" is null"

    • Some methods not found in java interop

    1.0.0-Beta12

    This update contains 9 features and improvements and 8 bug fixes.

    New Features

    • BL-438 - Zip Components, Utility and incorporating BIFS

    • BL-487 - Implement pagePoolClear()

    • - Add the ability to configure the CF transpiler

    • - Transpiler doesn't handle attributeCollection

    • - Zip Components, Utility and incorporating BIFS

    Improvements

    • - Compiler thread safety

    • - Implements SystemCacheClear()

    • - Allow "object" passed to throw to be a struct representation of an exception

    • - Added all missing boxlang types to BoxLangType class

    Bugs

    • - Lock expects timeout to be minimum of 1

    • - numeric literals with leading zeros are confused with octal values in java source

    • - getApplicationMetadata() fails before application listener is defined

    • - AST string values incorrectly unescaped outside of cfoutput

    Authors

    Information about the authors

    Luis Fernando Majano Lainez

    Luis Majano is a Computer Engineer who has been developing and designing software systems since 2000. During economic instability and civil war, he was born in San Salvador, El Salvador, in the late 70s. He lived in El Salvador until 1995 and then moved to Miami, Florida, where he completed his Bachelor of Science in Computer Engineering at .

    He is the CEO of , a consulting firm specializing in web development, BoxLang, Java development, and open-source professional services. He is the creator of ColdBox, ContentBox, CommandBox, WireBox, TestBox, LogBox, and anything "Box," and he contributes to over 250 open-source projects. He has a passion for learning and mentoring developers so they can succeed with sustainable software practices and the usage and development of open-source software. You can read his blog at

    BL-617
    BL-626
    BL-627
    BL-629
    BL-630
    BL-611
    BL-622
    BL-623
    BL-614
    BL-615
    BL-616
    BL-619
    BL-620
    BL-624
    BL-625
    BL-628
    BL-631
    BL-633
    BL-634
    BL-720
    BL-721
    BL-722
    BL-710
    BL-716
    BL-717
    BL-728
    BL-729
    BL-638
    BL-641
    BL-669
    BL-677
    BL-679
    BL-697
    BL-711
    BL-712
    BL-715
    BL-718
    BL-719
    BL-724
    BL-726
    BL-727

    BL-1375 Compat - Move Legacy Date Format Interception to Module-Specific Interception Point

  • BL-1381 allow box class to be looped over as collection

  • BL-1382 Rework event bus interceptors to accelerate during executions

  • BL-1383 Compat - Allow handling of decimals where timespan is used

  • BL-1387 Allow Numeric ApplicationTimeout assignment to to be decimal

  • BL-1372 string functions accepting null

  • BL-1374 onMissingTemplate event mystyped as missingtemplate

  • BL-1377 fileExists() not working with relative paths

  • BL-1378 optional capture groups throw NPE in reReplace()

  • BL-1379 array length incorrect for xml nodes

  • BL-1384 Numeric Session Timeout Values Should Be Duration of Days not Seconds

  • BL-1333
    BL-1351
    BL-1358
    BL-1363
    BL-1354
    BL-1359
    BL-1366
    BL-1370

    BL-479 - Address parser performance by limiting operator reserved words

  • BL-478 - Change template parsers to use SLL prediction mode

  • BL-477 - Improve parsing performance by only calculating lines of code on error

  • BL-474 - Add ValueRequiresOneOf Validator

  • BL-475 - Pretty printer incorrect for default case ending tag

    BL-491
    BL-490
    BL-438
    BL-486
    BL-485
    BL-483
    BL-480
    BL-484
    BL-481
    BL-482
    BL-476

    Luis is passionate about Jesus, tennis, golf, volleyball, and anything electronic. Random Author Facts:

    • He played volleyball in the Salvadorean National Team at the tender age of 17

    • His favorite books are The Lord of the Rings and The Hobbit (Geek!)

    • His first computer was a Texas Instruments TI-99 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)

    • He has a geek love for circuits, microcontrollers, and overall embedded systems.

    • He has, as of late, become a fan of organic gardening.

    Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!

    "Trust in the LORD with all your heart, and do not lean on your own understanding." Proverbs 3:5

    Florida International University
    Ortus Solutions
    Luis F. Majano
    www.luismajano.com

    1.0.0-Beta25

    December 13, 2024

    BoxLang Beta 25 Has Landed!

    This release takes BoxLang to the next level, delivering a mix of critical bug fixes, thoughtful improvements, and exciting new features designed to enhance your development experience. With Beta25, we’ve solidified and made the ASM ByteCode BoxPiler the default compiler, refined module, and logging management, and added long-requested query of queries and JSON-based logging encoders. Additionally, we’ve tackled critical issues around debugging, compatibility, and system settings to make this the most stable and feature-complete beta yet.

    At this point, we have a handful of small bugs open, which will completely certify all of the major Ortus frameworks like ColdBox, ContentBox, and over 50 modules. Complete certification is around the corner.

    As a bonus, we are almost ready to release our Hibernate ORM module (bx-orm) and move into a Release Candidate phase for our entire lineup. So please test test test, and give us your feedback.

    ✨ New Features

    • : createObject() now supports classloading arguments as the third argument.

    Easily manage and control classloading with arguments to enhance flexibility and modularity.

    • : Dynamic Task Management in Schedulers

    Added startupTask(task) to dynamically initialize tasks by name or task object.

    • : JSON-based Logging Support

    Appenders and root configurations now include JSON encoders for enhanced logging formats.

    • : Improved Scheduler Logging

    Scheduler logs are now effectively reported to provide better insights.

    • : Enhanced Module Logging

    Modules now have dedicated logs to improve debugging and diagnostics.

    • : New Event Lifecycle: onConfigurationLoad

    Introduced a new lifecycle event for IServices to optimize configuration handling.

    • : Enhanced Compatibility Assignments

    Assignments now accurately interpret null variables for better compatibility.

    • : New Logging Setting: statusPrinterOnLoad

    Added statusPrinterOnLoad for much-needed debugging of logging configurations.


    🛠 Improvements

    • : Streamlined Method Expectations

    Improved handling of methods that don’t expect return values for better consistency.

    • : Enhanced Session Cookie Controls

    Added missing controls for session cookie management to improve security and compliance.

    • : Bytecode Line Number Enhancements

    Added line number details to bytecode generated with ASM for improved debugging.

    • : ASM is Now the Default BoxPiler

    Streamlined the toolchain by making ASM the only default stock BoxPiler.

    • : Optimized Replace Operations

    Updated replaceAll() methods to use pre-compiled patterns for better performance.

    • : Unified Logging Configuration

    Consolidated logging startups and configurations for both servlet and non-servlet environments.

    • : Support for this.componentPaths

    Introduced implicit mapping support for more intuitive path management.

    • : Module Enable/Disable Support

    Modules can now be enabled or disabled using enabled in boxlang.json, removing double negatives like disabled.

    • : Forms Module Introduced

    A new module for handling forms was added, enhancing the BoxLang ecosystem.

    • : Improved Scope Assignment

    Allowed reassignment of a scope to a struct for more flexible programming.

    • : Collision Prevention in IClassRunnable Methods

    Prefixed methods to prevent naming collisions for safer execution.

    • : Graceful Module Unloading

    Added defensive coding for module unloading failures to ensure runtime stability.

    • : Consistent Struct Collector Outputs

    Resolved inconsistencies by ensuring collectors return Struct objects.

    • : Improved Parent Class Delegation

    Enhanced module class loaders to delegate certain parent classes to the parent loader exclusively.


    🐞 Bug Fixes

    • ASM and Debugging Fixes:

    , , , ,

    • Localization and Formatting Issues:

    , ,

    • Parsing Errors:

    , ,

    • Thread and Scope Resolution Bugs:

    , ,

    • Miscellaneous:

    , , ,

    1.0.0-Beta20

    October 25th, 2024

    🚀 Introducing BoxLang 1.0.0 Beta 20! 🚀

    This release brings another round of powerful tools and refinements to the BoxLang community, making development more dynamic and robust than ever. We’ve added new capabilities for debugging and tracing, expanded context-sensitive controls for thread management, and introduced new methods for fluent attachment handling.

    For deeper flexibility, our improvements enhance configurability, streamline session control, and add deeper levels of JSON serialization management. Plus, we’ve squashed a wide range of bugs, enhancing stability across database connections, date handling, and runtime compatibility with CFML.

    New Feature

    trace bif and component

    Setup the thread's context class loader when an application is defined with the correct loader from the Applications java settings

    showDebugOuput added to request box context to allow for tracer/debugging outputs

    new computeAttachmentIfAbsent, to make fluent attachments on IBoxAttachable implementations

    refactor escapeHTML to the lib we use instead of multiple functions

    DateTime objects don't have a len member method

    Improvements

    Add line break in dump console output

    Allow access to super scope from thread

    reuse config of validTemplateExtensions

    Add ability to deep merge config items from the environment.

    track current request context in thread

    improve concurrency of session ID creation

    Move from immutable verbiage to unmodifiable

    Need to set explicit `/` path on session cookies

    if calling serializeJSON() on a class, and the class is marked as not serializable, then return empty struct

    if calling serializeJSON() on a class, properties marked as not serialiable should be skipped.

    Arrays/Lists/Structs/Maps/Classes that have been visited already by JSON will not serialize again but show a recursion marker

    Bugs

    bx-compat-cfml datediff fails to convert string

    Update parser to allow for `@module` notations on imports and `new` operators

    NOT operator precedence not grabbing operators in the chain

    Java Doc implementation is stricter that ACF and Lucee

    Missed module class hierarchy to have the runtime class loader as the parent

    ortus.boxlang.runtime.events.InterceptorPool: Errors announcing [logMessage] interception ortus.boxlang.runtime.types.exceptions.BoxRuntimeException: An error occurred while attempting to log the message

    Dump not showing BoxLang type NullValue as null

    DBInfo schema and several other columns can be null, make sure you address it

    boxclass dump looping construct exception

    java class method not found

    argument collection optional param is null

    Cannot convert class ortus.boxlang.runtime.types.DateTime to SQL type requested due to com.mysql.cj.exceptions.WrongArgumentException - Conversion from ortus.boxlang.runtime.types.DateTime to TIMESTAMP is not supported.

    DatabaseException: There is no known date-time pattern for '09/24/2024' value at ortus.boxlang.runtime.jdbc.PendingQuery.executeStatement(PendingQuery.java:390)

    cannot get lenght of native java date time objects

    Can't cast [2021-01-01 12:00:00 pm] to a DateTime.

    1.0.0-Beta7

    July 26, 2024

    BoxLang Betas are released weekly.

    This is our seventh beta marker and we are incredibly excited of this beta marker since it now fully supports ColdBox for operation.

    Improvements

    web support error template only shows details of exceptions if IN debug mode else secure by default

    If you are using the MiniServer or CommandBox, then if an exception occurs, only in DEBUG MODE, will you get the exception stacktrace, details and more. This makes it secure by default of not exposing any potential data for exceptions.

    Consolidate the runtime into services without the need of getInstance()

    A simple internal improvement to improve locking and instance usage.

    New Features

    threadNew()

    This is a new BIF for BoxLang. We have a way to create threads using the thread{} component in both script and template, and we have threadJoin(), threadTerminate() but we never had a way to create threads functionally.

    Signature

    Examples

    Please note that the attributes is a struct of data that we will bind into the thread's local scope.

    Stream type and collector member methods

    Java streams are now a native BoxLang type, which for now we don’t try to coerce, but simply match any existing instance or subclass of java.lang.Stream. This means we can now add member methods to ANY stream from BoxLang source code and make Streams also dynamic:

    • .toBXArray()

    • .toBXStruct( [String type] )

    • .toBXQuery( [Query query] )

    Examples

    Collect stream of objects into BoxLang array

    Collect stream of Map entries into a struct

    Collect an array of structs into an existing query object

    Collect a stream of objects into a list

    orThrow( type, message ) for attempts

    Attempts now allow you to do a custom exception type and message. Check out the docs.

    ifSuccessful() alias to ifPresent() on attempts

    Attempts now allow you to have an alias to ifPresent() that's fluent: ifSuccessful(). Check out the docs.

    Bugs

    Parser detection for unparsed tokens only works if there are 2 or more tokens left

    Declaring UDFs in function context doesn't always work

    CFConfig datasources aren't importing due to lack of support for the 'dbdriver' key

    Runtime can deadlock due to syncronized methods

    NPE calling isNumeric()

    JSONSerialize() errors when useSecureJSONPrefix not a boolean

    Cannot call getWriter(), getOutputStream() already called

    empty url vars coming through as null

    Tasks

    Create tests for al valid and invalid dot and array access expressions

    1.0.0-Beta15

    September 20, 2024

    Welcome to Beta 15! This release brings several significant enhancements aimed at improving the efficiency and functionality of the CLI environment and continued bug fixing to bring our CFML compatibility to several client applications and Ortus Libraries. Key among these is the introduction of the bx-web-support module, which allows the CLI to interface with web server capabilities, making it an excellent tool for testing and feature auditing. Additionally, the merge capabilities within module settings have been refined to support deep merges from the configuration file, ensuring greater flexibility and control.

    Moreover, running scripts or classes via CLI execution now supports the automatic detection and execution of Application.bx|cfc, streamlining the process for developers. The new ToString dump template enhances debugging by enabling a concise display format for lists of Java objects, simplifying the analysis and debugging process.

    Overall, this beta release brings further stability for CFML applications migrating to BoxLang!

    New Features

    Look and execute for Application.bx|cfc when running scripts or classes via CLI execution

    We have always wanted even further CLI enhancements for applications built with BoxLang. Now you get it! BoxLang will look for an Application.bx|cfc whenever it executes a template or class and follow the process of application startup, settings, ORM, etc. The full life-cycle of an application but at the CLI level. This will allow you to completely test your web applications with no web server and even build CLI applications with easy application constructs!

    New bx-web-support module to support the CLI with web server capabilities. Great for testing, mocking and feature audits.

    We have released the bx-web-support module which will give you mocking, testing and auditing capabilities for CLI testing and runners. This means that your CLI applications will look and feel like a real web application with a real web server, but using our mock approaches.

    This module is still in it's alpha stages so expect much more development on it.

    Module settings should have a deep merge from the configuration file

    All module settings in your boxlang.json can now be deeply merged automatically by BoxLang.

    Add a new ToString dump template that will take a list of java objects to display them in short hand format

    We will be easing the visibility of certain human readable Java classes in our dump templates.

    Handle single values in arrayAppend merge=true

    A nice feature to support further merging techniques with arrays.

    Improvements

    dump improvement of UI when using expand/collapse

    Show errors in class pseudo constructor in tag context

    List utils need to trim all values when converting to arrays

    LocalDateTime not showing in dumps as a date/time string, but as a Java Object

    Update date/time and instant dump templates to be less verbose and more functional

    Allow CF tag islands and template islands to be nested more than one level deep.

    Merge CF lexer and grammar for faster parsing and more accurate lexing

    Make tag expression parsing smarter

    expandPath() must ignore invalid paths, just returning the input

    More IO BIFs need to ignore invalid paths

    Bugs

    script block parsing can be tricked by comments

    Lucee allows properties to be anywhere in the pseduoconstructor of a class, not just at the top

    flush component only flushes up one buffer, not all the way

    Boxlang doesn't parse milliseconds in datetime string

    Date "string" doesn't have date time member functions available

    Querynew failing with more than one column defined

    Regular Expression Syntax not supported

    Metadata visitor doesn't support struct annotations with unquoted keys

    Hyper module failing

    bx-compat cfloop requires "index" when it shouldn't

    transaction shouldn't require global DSN

    cfproperty tag lucee allows non quoted properties

    Class name sensitivity based on provided rather than class found

    No reading dump templates due to pathing incorrectly in debug mode

    Static support not compatible with CFML

    javacast not actually casting as expected

    functions in variables scope vs values in variables scope

    bx-compat unquoted hashed expressions cause compiler error

    serializeJSON errors when serializing a function

    Sentinel loop with missing expressions fails

    mid() It does not remove characters if the count is more than the length

    Cannot invoke "ortus.boxlang.runtime.types.IStruct.putAll(java.util.Map)" because "recipient" is null

    1.0.0-Beta13

    September 6, 2024

    This release introduces several new features aimed at enhancing the usability and functionality of BoxLang. We have closed a tremendous amounts of bugs on this release in order to bring more compatibility and stability to BoxLang. We have also started to introduce performance enhancements and more innovations as we progress towards final release.

    Enjoy!

    New Features

    Writedump output support

    We have finalized the console output for the dump component, but we have also added the following ticket:

    New dump event to listen when an non-core output is detected so modules can handle it. onMissingDumpOutput

    Which will allow module developers to collaborate their own output destinations for any dump in the language. This is something we have wanted for years and it's now a possibility. Just listen to the onMissingDumpOutput interception point, you get all the arguments to the BIF or component and you decide where things will go. VScode Dump Panel, here we come.

    The console output has also been enhanced where everything will be pretty printed, including labels.

    Ability to mark a @BoxBif as excluded from documentation

    This is more of an internal documentation process for the team.

    New dump template for Java instants

    Java Instants will now be dumped nicely with an internal representation and a human readable representation.

    dump showUDFs

    All the arguments for dumps are now available including this one for controlling the dumping of UDFs on classes.

    Improvements

    Simplify BoxLang class dumps

    Add output and format to dump

    Some BIFs not fully supporting BigDecimal values

    access e.cause as shortcut for e.getCause()

    When creating an abstract class a new `AbstractClassException` is thrown. Great for testing frameworks

    Bugs

    queryaddcolumn ignores the datatype

    Issue with #dateTimeFormat(now(),'mm-dd-yyyy')# function returning incorrect results

    structnew( "linked" ) doesn't work

    argumentCollection doesn't work with implicit constructor

    directory component must always return query

    BoxNewTransformer using hard-coded context name

    toNumeric() not accepting radix values of 2-36

    cannot cast [x to object] on generic caster when using `QuerySetCell()`

    Issue with `Duplicate()` Function Causing Null Pointer Exception in BoxLang

    final keyword not working on this scope

    directoryList() filters are not working as closures/lambdas as they are hardcoded as strings

    Cannot invoke "ortus.boxlang.runtime.types.Query.isEmpty()" because "this.query" is null

    Multiple pipe-delimited glob patterns are not working as directoryList filters

    DuplicationUtil not doing deep clones of structs according to all types

    Throwing custom type exceptions just shows `custom` as the type instead of the actual type in the throw

    remote access not treated as public but as private for functions

    Interfaces don't support multiple inheritance

    CFC source type not detected correctly for abstract or final classes

    Metadata with : in them in cfml mode not treated correctly

    xml entity parsing issue when calling `toString()` on Java objects

    1.0.0-Beta16

    Welcome to Beta 16! This release focuses on web support functionality and contains a number of improvements and bug fixes for HTTP operations, including multi-part file uploads and error handling. It also provides enhancements to Java interoperability, dump template output, and metadata introspection.

    Overall, this beta release brings further stability for CFML applications migrating to BoxLang!

    Release notes - BoxLang - 1.0.0-Beta16

    New Feature

    Implement timeout for HTTP requests

    Multi-part request support in HTTP

    Improvement

    Add text-based toString() method for Queries (used in console dumps)

    for in Java transformer not mapping source line numbers for start of loop

    Make include case insensitive

    Enhance metadata visitor to process extends

    add fieldNames key to form scope

    Auto casting for URI and URL classes to string

    Handle bad gateways in HTTP component

    Allow for multiple form fields with the same name in HTTP component

    autocast InetSocketAddress to string

    Bug

    Fix for overeager escaping of quantifier sequences in REFind

    High order closures creating incorrect AST when parsing

    Update DateTime Parsing to handle the Common Javascript Date.toString format

    Module settings no longer overriding after deep merge function added

    Java interop doesn't find method by argument types when passing null

    Can't assign to List due to incorrect validation in referencer

    content-type isn't always getting defaulted in some requests

    for/in loop over struct should get String keys instead of BL Key instances

    showUDFs not cascading down in dump levels

    using cfcookie should update cookie scope

    Fix argument order for FileUpload

    1.7.0

    November 4, 2025

    Introduction

    BoxLang 1.7.0 brings significant performance improvements, powerful new features for modern web development, and enhanced database capabilities. This release introduces Server-Sent Events (SSE) support for building real-time applications and AI agents, a new JDBC Cache Store for distributed caching, and bytecode compatibility versioning for improved module management. Performance optimizations across scheduled tasks, class loading, and ASM generation deliver faster execution, while over 40 bug fixes improve stability in file operations, HTTP handling, database queries, and CFML compatibility.

    1.0.0-Beta24

    December 2, 2024

    Introducing BoxLang 1.0.0 Beta 24!

    We’re excited to announce the release of Beta 24, packed with powerful new features, essential bug fixes, and impactful improvements that enhance performance and security. This release brings more robust logging capabilities, enhanced configuration flexibility, and new query-handling methods to streamline your development experience. We’ve also squashed several parsing bugs, ensuring smoother code execution.

    Whether you’re optimizing your runtime with custom logging encoders or leveraging the new queryColumnList for seamless data manipulation, Beta 24 is designed to empower developers with a more secure, customizable, and efficient development environment.

    1.0.0-Beta22

    The BoxLang 1.0.0-Beta22 release includes several improvements, bug fixes, new features, and stories. Key improvements include enhanced redirection for the Miniserver, better transactional event broadcasting, and added convenience methods like getRequestContext() and getApplicationContext(). Bug fixes address issues such as JSON deserialization, whitespace management, and various errors related to data types and loops. New features include support for multiple statements inside queries and a new datasourceRegister() BIF for easier SaaS integrations.

    Release Notes

    New Features

    BL-123 Implement multiple statements inside queries

    BL-383 new bif: datasourceRegister() to allow for easy saas integrations to create datasources

    BL-658 MIgrate AST Capture to it's own experimental flag

    BL-748 Add getApplicationContext() method on all contexts for convenience, especially when calling from CF/BL

    Improvement

    BL-730 Miniserver needs to 302 redirect when hitting a directory without the trailing slash

    BL-734 Broadcast Transactional events at the Application listener-level

    BL-735 Allow unregistering a java class (IInterceptor) from an InterceptorPool

    BL-737 Add getRequestContext() method on all contexts for convenience, especially when calling from CF/BL

    BL-738 Allow output from functional wrappers

    BL-740 Autocast simple values to Keys when calling java methods from BL

    BL-741 Allow :: static access to be chained to any expression

    BL-746 Add toLegacyDate BIF and Member Function to Compat module

    BL-751 Make generated getters return null when property is not initialized

    BL-116 Implement unfinished query options

    Bug

    BL-694 Fix tests that fail when using ASM

    BL-695 large json fails to deserialise with bx-compat

    BL-714 Add Whitespace Management

    BL-731 dump errors with compat installed due to null variable

    BL-733 RandRange seems to never return upper range

    BL-736 JDBC Transaction listeners not firing upon transaction event announcement

    BL-739 shebang checks in BoxRunner don't nicely handle invalid file paths

    BL-743 WDDX not parsing booleans correctly

    BL-744 Cannot cast ortus.boxlang.runtime.types.DateTime to java.util.Date

    BL-745 parseDateTime failing

    BL-747 for (sentinel) loop is evaluating the step/increment expression one final time too many when a break is used

    BL-752 error using negative indices to get characters from strings

    BL-754 error: integer number too large

    BL-755 SerializeJSON not working with named params

    BL-544
    BL-559
    BL-574
    BL-580
    BL-581
    BL-503
    BL-545
    BL-555
    BL-558
    BL-567
    BL-569
    BL-570
    BL-571
    BL-576
    BL-579
    BL-434
    BL-546
    BL-547
    BL-550
    BL-551
    BL-552
    BL-553
    BL-557
    BL-561
    BL-562
    BL-563
    BL-564
    BL-565
    BL-566
    BL-568
    BL-572
    BL-573
    BL-575
    BL-577
    BL-578
    BL-582
    BL-583
    BL-142
    BL-508
    BL-489
    BL-504
    BL-507
    BL-497
    BL-499
    BL-501
    BL-517
    BL-518
    BL-223
    BL-471
    BL-492
    BL-493
    BL-494
    BL-498
    BL-500
    BL-502
    BL-505
    BL-506
    BL-509
    BL-510
    BL-511
    BL-512
    BL-513
    BL-514
    BL-515
    BL-516
    BL-521
    BL-522
    BL-603
    BL-604
    BL-586
    BL-589
    BL-590
    BL-596
    BL-597
    BL-599
    BL-600
    BL-601
    BL-602
    BL-584
    BL-585
    BL-587
    BL-588
    BL-591
    BL-592
    BL-593
    BL-594
    BL-595
    BL-598
    BL-606
    BL-117
    BL-670
    BL-684
    BL-688
    BL-689
    BL-698
    BL-672
    BL-673
    BL-683
    BL-686
    BL-687
    BL-690
    BL-693
    BL-703
    BL-707
    BL-708
    BL-709
    BL-640
    BL-645
    BL-663
    BL-668
    BL-671
    BL-675
    BL-676
    BL-678
    BL-680
    BL-696
    BL-697
    BL-701
    BL-702
    BL-704
    BL-705
    BL-121
    BL-699
    BL-794
    BL-828
    BL-829
    BL-832
    BL-833
    BL-846
    BL-682
    BL-706
    BL-760
    BL-766
    BL-784
    BL-787
    BL-788
    BL-791
    BL-809
    BL-812
    BL-822
    BL-830
    BL-831
    BL-839
    BL-694
    BL-742
    BL-759
    BL-762
    BL-760
    BL-819
    BL-825
    BL-820
    BL-823
    BL-824
    BL-827
    BL-813
    BL-815
    BL-817
    BL-826
    BL-836
    BL-841
    BL-845
    .toBXList( [String delimiter] )
    BL-376
    BL-392
    BL-374
    BL-388
    BL-390
    attempt
    BL-391
    attempt
    BL-373
    BL-377
    BL-378
    BL-379
    BL-380
    BL-381
    BL-385
    BL-386
    BL-372
    🚀 Major Highlights

    🎯 Server-Sent Events (SSE)

    New SSE() BIF and Emitter for web runtimes enables real-time server-to-client event streaming, perfect for building AI agents, live dashboards, progressive loading experiences, and real-time notifications. The implementation includes automatic keep-alive, CORS support, async execution, and graceful timeout handling.

    Basic Usage:

    AI Streaming with Async Execution:

    Cross-Origin Streaming:

    Available Parameters:

    • callback (required) - Closure/lambda that receives the emitter object

    • async (default: false) - Run callback in background thread (non-blocking)

    • retry (default: 0) - Client reconnect interval in milliseconds

    • keepAliveInterval (default: 0) - Auto-send keep-alive comments interval

    • timeout (default: 0) - Maximum execution time for async mode

    • cors (default: "") - CORS origin (* for all, or specific domain)

    Emitter Methods:

    • send( data, [event], [id] ) - Send SSE event (complex data auto-serialized to JSON)

    • comment( text ) - Send SSE comment for keep-alive

    • close() - Gracefully close the stream

    • isClosed() - Check if client disconnected

    Implementation Features:

    • Automatic first-byte flush to establish connection quickly

    • Large data chunking (splits >32KB lines automatically)

    • Multi-line data support with proper SSE formatting

    • Client disconnect detection with graceful cleanup

    • Proxy/nginx buffering disabled for real-time delivery

    🗄️ JDBC Cache Store

    New distributed cache store backed by JDBC databases, enabling cache sharing across multiple BoxLang instances. Perfect for horizontal scaling scenarios where multiple application servers need to share cached data.

    Basic Configuration:

    Advanced Configuration with Eviction:

    Configuration Options:

    • datasource (required) - Name of the datasource to use for storage

    • table (default: "boxlang_cache") - Database table name for cache storage

    • autoCreate (default: true) - Automatically create table and indexes if missing

    • Plus all standard BoxCache properties (maxObjects, evictionPolicy, evictCount, etc.)

    Supported Databases:

    • Oracle

    • MySQL / MariaDB

    • PostgreSQL

    • Microsoft SQL Server

    • Apache Derby

    • HSQLDB

    • SQLite

    The implementation automatically detects the database vendor and generates optimized SQL for each platform, including proper handling of:

    • Database-specific data types (CLOB, TEXT, LONGTEXT, etc.)

    • Vendor-specific eviction queries (LIMIT, TOP, FETCH FIRST)

    • Index creation strategies

    • Transaction handling

    Features:

    • Distributed: Mark as distributed store - cache data persists across instances

    • Automatic Schema Management: Creates table and indexes on first use

    • Serialization: Uses Base64-encoded object marshalling for complex types

    • Performance: Pre-compiled SQL statements for all operations

    • Eviction Support: Full support for LRU, LFU, and other eviction policies

    • Metadata Tracking: Stores hits, timeouts, and access timestamps

    All cache stores now expose isDistributed() method for ecosystem tools to detect distribution capabilities.

    🌳 BoxAST() - AST Generation

    New BoxAST() BIF enables programmatic access to BoxLang's Abstract Syntax Tree (AST), perfect for building code analysis tools, linters, formatters, and code generation utilities. It supports parsing BoxLang script/template syntax as well as CFML/ColdFusion syntax for migration and compatibility tools.

    Parameters:

    • source - BoxLang/CFML source code to parse

    • filepath - Path to file to parse (alternative to source)

    • returnType - Output format: "struct" (default), "json", or "text"

    • sourceType - Syntax type: "script" (default), "template", "cfscript", or "cftemplate"

    Use Cases:

    • Code Analysis: Build custom linters and static analysis tools

    • Code Generation: Generate BoxLang code from templates or DSLs

    • Formatters: Create custom code formatting utilities

    • Documentation Generators: Extract function signatures and comments

    • Refactoring Tools: Analyze and transform code structures

    • IDE Tooling: Power syntax highlighting and code intelligence features

    • Migration Tools: Parse and analyze CFML code for BoxLang migration

    🔧 Bytecode Compatibility Versioning

    BoxLang now implements bytecode compatibility versioning, ensuring compiled classes remain compatible across runtime versions and improving module stability.

    🤖 Core Runtime Updates

    Performance Improvements

    • Scheduled Tasks: Significant performance boost by introducing non-concurrent maps for logging and closure suppliers

    • Static Initializers: Optimized execution of static class initializers

    • ASM Generation: Streamlined bytecode generation by eliminating disk-based class file operations

    • Cache Stores: Performance tuning across all cache store implementations

    Enhanced Dumping

    • Renamed all dump() member methods to .bxDump() to prevent conflicts with user-defined methods

    • Improved class dumping with better error handling for restricted Java fields

    • Fixed Java time type dumping (java.sql.Time)

    • Better handling of recursive class references in JSON serialization

    Module System Enhancements

    • Added missing properties to getModuleInfo() struct snapshot

    • Fixed module publicMapping registration

    • Improved IService lifecycle by ensuring onConfigurationLoad() is called correctly

    • Better validation of template URIs

    HTTP Component Improvements

    • Added client certificate functionality support:

    • Fixed double encoding of query parameters in HTTPParam

    • Better handling of getAsBinary=no for CFML compatibility

    • Proper Optional unwrapping in HTTP result responses

    📡 MiniServer Runtime Updates

    • Fixed rewrite file extension handling - no longer rewrites requests unnecessarily

    • Improved request body handling for empty payloads

    • Better error messages for empty request bodies

    🤖 Servlet Runtime Updates

    • Fixed relative path resolution for mappings

    • Enabled BOXLANG_DEBUG environment variable support

    • Improved session management - fixed jsessionid cookie handling to prevent AWS WAF issues

    • Better handling of in-progress onApplicationStart() for concurrent requests

    🥊 Developer Experience

    Dynamic Object Creation

    Enhanced createDynamicProxy() and createObject() to accept custom class loaders:

    IStruct Convenience Method

    New getAsChar() method on IStruct for convenient character extraction:

    Configuration Improvements

    • JSON placeholders now applied immediately upon reading for consistent key replacement

    • Better handling of hyphens in pre-annotations to match post-annotation behavior

    • Fixed ignore of wildcard * in valid template extensions when searching for Application descriptors

    🐛 Notable Bug Fixes

    Database & Stored Procedures

    • Fixed MSSQL connection issues when specifying username and password in cfquery

    • Resolved multiple result set returns in CFStoredProc

    • Fixed stored procedure parameter errors and type casting for timestamps

    • Improved dynamic SQL type handling in CF transpiler

    File Operations

    • Fixed fileCopy() not respecting overwrite parameter

    • Corrected file upload handling:

      • Files smaller than 10KB now properly stored on disk

      • Proper directory creation for absolute destination paths

      • Fixed template-relative destination path handling

      • Empty allow argument now treated correctly

    • Fixed getFileInfo() returning incorrect type string for directories

    • Resolved expandPath() using wrong base path when Application.bx in different directory

    List Operations

    • Fixed listDeleteAt() incorrect behavior in both modes

    • Resolved appending null to list failures

    Component & Class Handling

    • Better error messages for import statements in class bodies

    • Fixed class dump output showing keys twice instead of values

    • Improved loose struct converter error handling

    • Fixed duplicate() failures when encountering Optional types

    Mail & Dates

    • Fixed bx:mail component string attribute handling for useSSL/useTLS

    • Resolved dateConvert() errors

    • Added handling for string dates with common masks

    Path & Mapping

    • Normalized mapping paths with ../ correctly

    • Fixed CGI scope mapping returning null values

    • Improved abort exception handling (no longer caught inappropriately)

    Dump Operations

    • Fixed CFDUMP and WRITEDUMP file output functionality

    Windows Compatibility

    • Resolved Windows BoxLang REPL regression

    🔧 Configuration Updates

    No configuration changes required for this release. New features like SSE and JDBC cache store are opt-in and require explicit configuration.

    ⚡ Migration Notes

    Breaking Changes

    Dump Method Rename: All built-in member methods named dump() have been renamed to .bxDump() to avoid conflicts with user-defined methods. If you were calling .dump() on built-in objects, update to .bxDump():

    Compatibility Improvements

    • Enhanced CFML compatibility for HTTP component behaviors

    • Better handling of empty file upload allow parameter

    • Improved stored procedure result set handling

    • More accurate CGI scope value mapping


    🎶 Release Notes

    Release notes - BoxLang - 1.7.0

    Improvements

    BL-1808 HTTP Component - Support Client Cert Functionality

    BL-1818 allow hyphen in pre annotations to match post annotations

    BL-1825 Performance improvement of all scheduled task calls by introducing non concurrent maps for logging and closure suppliers

    BL-1830 Don't rewrite miniserver requests with rewrite file extension

    BL-1836 Apply placeholders to JSON as soon as it's read to ensure all keys are replaced

    BL-1838 Improve performance of running static initializer on class

    BL-1839 Added missing properties to getModuleInfo() struct snapshot

    BL-1846 Validate request URIs

    BL-1848 Optimize ASM generation by not relying on disk class files

    BL-1849 dump class improvements

    BL-1853 Component annotation for ignoring ignore outpout only setting

    BL-1855 Component annotation for auto-evaluating interpolated expressions

    BL-1863 Rename all dump() member methods to be .bxDump() to avoid conflicts with actual methods named dump()

    BL-1864 Catch Java access errors when getting Fields dynamically in class dump

    BL-1865 Allow createDynamicProxy(), createObject() to accept a class loader

    BL-1866 Ignore valid template extension setting of * when searching for Application descriptors

    BL-1867 can't dump java.sql.Time

    BL-1877 Performance tuning on cache stores

    New Features

    BL-1791 Implement bytecode compat version

    BL-1861 New getAsChar() on IStruct for convenience

    BL-1875 New JDBCStore for the Box Cache

    BL-1876 Cache stores now have a isDistributed() interface method which allows cache providers and eco system to tell if the store can distribute content or be local only

    BL-1880 New SSE() BIF and Emitter for Web Runtimes to allow for server side event streaming. Especially great when building AI Agents

    BL-1883 New BoxAST() bif to help you return the AST of source or a filepath

    Bugs

    BL-1376 specifying `username` and `password` throws 'unable to open connection' in cfquery - mssql

    BL-1685 CFStoredProc does not return multiple result sets when using a statement like an insert as first query

    BL-1809 Servlet resolution of relative paths can return incorrect mapping

    BL-1810 Prevent Double Encoding of Query Params passed by HTTParam

    BL-1811 loose struct converter can error on getting public fields

    BL-1812 Don't catch abort exceptions

    BL-1814 appending null to list fails

    BL-1815 listDeleteAt() is not working correctly on cfml compat mode or not

    BL-1816 Stored Procedure errors out on missing parameter

    BL-1817 FileCopy bif using overwrite is not using it.

    BL-1820 mapping paths with ../ not always normalized

    BL-1821 recursive class references cause stack overflow on JSON serialization

    BL-1822 Compat: HTTP getAsBinary=no not always honored in other engines

    BL-1823 Duplicate Fails When Encountering Optional

    BL-1824 HTTP Component Returns Raw Optional for Result response When No Timeout is Specified

    BL-1829 Module publicMapping is not being registered

    BL-1831 dateConvert is throwing an error

    BL-1833 bx:mail not handling string useSSL or useTLS attributes

    BL-1834 CFDUMP and WRITEDUMP do not dump to a file

    BL-1837 Instances of IService in BL Modules never call onConfigurationLoad

    BL-1840 CF transpiler doesn't catch dynamic sql type on proc param

    BL-1841 BOXLANG_DEBUG env var not used in servlet

    BL-1842 Class dump doesn't output this scope values, just keys twice

    BL-1845 subsequent requests do not respect in-progress onApplicationStart()

    BL-1847 I am getting an error after server forget and server start

    BL-1851 Better error for Import Statements in Class bodies

    BL-1854 Web Compat: Empty `allow` argument to FileUpload is treated as "All" by other Engines

    BL-1856 MiniServer Exchange GetRequestBody Method Throws Error when RequestBody Is Empty

    BL-1857 GetFileInfo Returns Incorrect `type` string for Directory

    BL-1858 File Uploads smaller than 10KB not being stored on disk

    BL-1860 expandPath() uses wrong base path when application.xx is in different dir

    BL-1870 stored proc param not casting timestamp

    BL-1871 Regression Windows Boxlang REPL

    BL-1872 FileUpload - When Temp directory is passed in explicitly in absolute destination path, directories should be created

    BL-1873 FileUpload - Ensure correct handling for template relative destination paths

    BL-1874 jsessionid cookie value set to null - breaks AWS WAF

    BL-1878 Mapping CGI scope returns null values

    BL-1879 Add handling for string dates as a common mask

    🐞 Bug Fixes

    • BL-797: Parsing issue fixed when using a < symbol before a tag. No more parsing hiccups!

    • BL-798: = sign after an if tag? No problem now! Fixed to handle this scenario smoothly.

    • BL-799: Parentheses confusion resolved! Opening parentheses (afterword operators will no longer be mistaken for function calls.

    • BL-800: Environmental safety improved: BOXLANG_DEBUG will now be parsed only if non-null to prevent unexpected behavior.

    ✨ New Features

    Improved Logging

    BoxLang's logging features have been completely revamped in preparation for its stable release. You also have fine-grain control over them, and module developers will be able to register and leverage custom loggers and appenders.

    Please note that the logsDirectory setting has been moved from the root of the boxlang.json to the new logging section.

    Check out the new configuration:

    JSON Anyone?

    We have added support for JSON Lines log files. You can now switch the default encoder for the log files from text to json and see the JSON log files in full splendor!

    • BL-792: Introducing CFConfig support and named loggers for more precise control over your logging setup!

    • BL-793: Added the ability to configure logging items, giving you more flexibility in managing your logs.

    • BL-803: Choose your logging format! You can now select text and JSON logging encoders for better runtime output customization.

    \

    📈 Improvements\

    • BL-782: Refined the LoggingService to encapsulate all logging characteristics, streamlining log management.

    • BL-783: Strengthened security by disabling absolute path logging and prohibiting custom log extensions. Your logs are safer now!

    • BL-785: Upgraded logging to follow ISO8601 date/time format and threading standards for more standardized logs.

    • BL-786: Replaced FileAppender with RollingFileAppender to better handle large log files through automatic rotation.

    • BL-795: Introduced queryColumnList BIF and a columnList() member method for easier Query column management.

    • BL-804: Enhanced support for customTagPaths in Application.cfc/bx, expanding customization capabilities.

    createObject( "java", "HelloWorld", [ "/libs/paths" ]
    threadNew( lambda/closure, [attributes={}], [threadName], [priority=normal] )
    threadNew( () => {
        printLn( "thread is done!" );
        sleep( 1000 );
        result = "done";
    } );
    
    threadNew( () => calculateOrder( invoice ), {invoice:myData}, "order-builder", "high" )
    foods = [ 'apples', 'bananas', 'pizza', 'tacos' ];
    result = foods.stream().parallel().toBXArray();
    
    import java.util.stream.IntStream;
    result = IntStream.range(1, 6).toBXArray();
    foods = { 'apples' : 'healthy', 'bananas' : 'healthy', 'pizza' : 'junk', 'tacos' : 'junk' };
    result = foods.entrySet()
        .stream()
        .filter( e -> e.getValue() == 'healthy' )
        .toBXStruct();
    
    
    data = [ 'd' : '', 'c' : '', 'b' : '', 'a' : '' ];
    result = data.entrySet().stream().toBXStruct( "sorted" );
    qry = queryNew( "name,title", "varchar,varchar" );
    
    [
      	{ name: "Brad", title: "Developer" },
      	{ name: "Luis", title: "CEO" },
      	{ name: "Jorge", title: "PM" }
    ].stream().toBXQuery( qry );
    foods = [ 'apples', 'bananas', 'pizza', true ];
    foods.stream().toBXList();
    
    [ "www", "google", "com" ].stream().toBXList( "." )
    // Simple synchronous streaming
    SSE( ( emitter ) => {
        emitter.send( "Hello from server!" );
        emitter.send( { status: "processing", progress: 25 }, "update" );
        emitter.close();
    } );
    // Non-blocking AI response streaming
    SSE(
        callback: ( emitter ) => {
            var response = callAIService();
            while( !emitter.isClosed() && response.hasMoreTokens() ) {
                emitter.send( response.getNextToken(), "token" );
            }
            emitter.send( { complete: true }, "done" );
        },
        async: true,
        keepAliveInterval: 30000,  // Send keep-alive every 30s
        timeout: 300000            // Close after 5 minutes max
    );
    // Enable CORS for cross-domain requests
    SSE(
        callback: ( emitter ) => {
            emitter.send( { message: "Hello from API" }, "greeting", 1 );
        },
        cors: "*"  // or specific origin: "https://app.example.com"
    );
    // Configure JDBC cache store in boxlang.json
    {
      "caches": {
        "distributedCache": {
          "provider": "BoxCache",
          "properties": {
            "objectStore": "JDBCStore",
            "datasource": "myDatasource",
            "table": "boxlang_cache",
            "autoCreate": true
          }
        }
      }
    }
    {
      "caches": {
        "sharedCache": {
          "provider": "BoxCache",
          "properties": {
            "objectStore": "JDBCStore",
            "datasource": "prodDB",
            "table": "app_cache",
            "autoCreate": true,
            // Standard BoxCache properties
            "maxObjects": 1000,
            "evictionPolicy": "LRU",
            "evictCount": 100,
            "defaultTimeout": 3600,
            "defaultLastAccessTimeout": 1800,
            "reapFrequency": 300
          }
        }
      }
    }
    // Parse BoxLang source code using BIF
    ast = BoxAST( source: "x = 1 + 2; y = x * 3;" );
    
    // Or use the convenient string member method
    code = "function hello() { return 'world'; }";
    ast = code.toAST();
    
    // Parse from a file
    ast = BoxAST( filepath: "myScript.bx" );
    
    // Return as JSON for external tools
    astJson = BoxAST(
      source: "function hello() { return 'world'; }",
      returnType: "json"
    );
    
    // Or with member method
    astJson = "x = 1 + 2;".toAST( returnType: "json" );
    
    // Return as text representation
    astText = BoxAST(
      filepath: "complex.bx",
      returnType: "text"
    );
    
    // Parse BoxLang template syntax
    templateAst = BoxAST(
      source: "<bx:output>#now()#</bx:output>",
      sourceType: "template"
    );
    
    // Parse CFML/ColdFusion script (for migration tools)
    cfScriptAst = BoxAST(
      source: "cfset x = 1; cfloop from='1' to='10' index='i' { writeOutput(i); }",
      sourceType: "cfscript"
    );
    
    // Parse CFML/ColdFusion template (for migration tools)
    cfTemplateAst = BoxAST(
      source: "<cfset x = 1><cfoutput>#x#</cfoutput>",
      sourceType: "cftemplate"
    );
    http url="https://secure-api.com" {
      httpparam type="certificate" file="client-cert.p12" password="secret";
    }
    // Use custom class loader for dynamic object creation
    customLoader = createObject( "java", "java.net.URLClassLoader" )
      .init( [ url ] );
    
    proxy = createDynamicProxy(
      listener,
      [ "com.example.Interface" ],
      customLoader
    );
    struct = { "code": "A" };
    charValue = struct.getAsChar( "code" ); // Returns Character 'A'
    // Old
    array.dump();
    
    // New
    array.bxDump();
    // Logging Settings for the runtime
    "logging": {
    	// The location of the log files the runtime will produce
    	"logsDirectory": "${boxlang-home}/logs",
    	// The maximum number of days to keep log files before rotation
    	// Default is 90 days or 3 months
    	// Set to 0 to never rotate
    	"maxLogDays": 90,
    	// The maximum file size for a single log file before rotation
    	// You can use the following suffixes: KB, MB, GB
    	// Default is 100MB
    	"maxFileSize": "100MB",
    	// The total cap size of all log files before rotation
    	// You can use the following suffixes: KB, MB, GB
    	// Default is 5GB
    	"totalCapSize": "5GB",
    	// The root logger level
    	// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
    	// If the runtime is in Debug mode, this will be set to DEBUG
    	"rootLevel": "WARN",
    	// Default Encoder for file appenders.
    	// The available options are "text" and "json"
    	"defaultEncoder": "text",
    	// A collection of pre-defined loggers and their configurations
    	"loggers": {
    		// The runtime main and default log
    		"runtime": {
    			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
    			// Leave out if it should inherit from the root logger
    			//"level": "WARN",
    			// Valid values are: "file", "console",
    			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
    			// Please note that we only use Rolling File Appenders
    			"appender": "file",
    			// Use the defaults from the runtime
    			"appenderArguments": {},
    			// The available options are "text" and "json"
    			"encoder": "text",
    			// Additive logging: true means that this logger will inherit the appenders from the root logger
    			// If false, it will only use the appenders defined in this logger
    			"additive": true
    		},
    		// The modules log
    		"modules": {
    			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
    			// Leave out if it should inherit from the root logger
    			//"level": "WARN",
    			// Valid values are: "file", "console",
    			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
    			// Please note that we only use Rolling File Appenders
    			"appender": "file",
    			// Use the defaults from the runtime
    			"appenderArguments": {},
    			// The available options are "text" and "json"
    			"encoder": "text",
    			// Additive logging: true means that this logger will inherit the appenders from the root logger
    			// If false, it will only use the appenders defined in this logger
    			"additive": true
    		},
    		// All applications will use this logger
    		"application": {
    			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
    			// Leave out if it should inherit from the root logger
    			"level": "TRACE",
    			// Valid values are: "file", "console",
    			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
    			// Please note that we only use Rolling File Appenders
    			"appender": "file",
    			// Use the defaults from the runtime
    			"appenderArguments": {},
    			// The available options are "text" and "json"
    			"encoder": "text",
    			// Additive logging: true means that this logger will inherit the appenders from the root logger
    			// If false, it will only use the appenders defined in this logger
    			"additive": true
    		},
    		// All scheduled tasks logging
    		"scheduler": {
    			// Valid values are in order of severity: ERROR, WARN, INFO, DEBUG, TRACE, OFF
    			// Leave out if it should inherit from the root logger
    			"level": "INFO",
    			// Valid values are: "file", "console",
    			// Coming soon: "smtp", "socket", "db", "syslog" or "java class name"
    			// Please note that we only use Rolling File Appenders
    			"appender": "file",
    			// Use the defaults from the runtime
    			"appenderArguments": {},
    			// The available options are "text" and "json"
    			"encoder": "text",
    			// Additive logging: true means that this logger will inherit the appenders from the root logger
    			// If false, it will only use the appenders defined in this logger
    			"additive": true
    		}
    	}
    },

    1.0.0-Beta19

    October 18th, 2024

    Welcome to the latest release of BoxLang, where innovation takes center stage with groundbreaking enhancements and features designed to elevate your development experience. With the introduction of the ASMBoxPiler, we're pioneering a direct pathway to converting BoxLang code into highly optimized Java bytecode, offering an unprecedented boost in performance and efficiency. By eliminating traditional bottlenecks, we're empowering developers to achieve seamless integration with Java environments, transforming the way applications are built and executed. Prepare to explore the full potential of your projects with this transformative update!

    New Features

    ASMBoxPiler to do direct Java bytecode creation

    With the implementation of the ASMBoxPiler, developers can now compile BoxLang source code directly into Java bytecode, streamlining the process and improving performance by over 4 times. This feature eliminates the intermediate steps previously required for code execution, resulting in faster compilation times and seamless integration with Java environments.

    The JavaBoxPiler will remain in BoxLang as it's an integral debugging piece. It might be moved later to it's own module, but having the capability to transpile BoxLang/CFML code to Java will remain.

    The direct bytecode generation allows for enhanced optimization and leverages the full potential of Java's JVM, leading to more efficient and scalable applications. By default, right now this is an experimental feature and it will need to be turned ON in order to use it via our boxlang.json configuration, via the compiler : "asm"

    Star-import for boxlang classes

    You can now use * imports for BoxLang classes, which allows you to bring in all the classes found in the imported package into the class namespace so you can create them by just using their name. In practice, the use of star-imports is a trade-off between convenience and potential issues such as namespace collisions. While they can make code more concise, especially when many classes from a package are needed, they may also import unintended classes, leading to ambiguities. Therefore, it's generally recommended to use specific imports when only a few classes are required and reserve star-imports for when numerous classes from the same package are genuinely required.

    Java wildcard imports from loaded jars

    The feature enhances import capabilities by allowing Java wildcard imports from loaded JAR files. This means you can use the * notation to import all classes within a JAR package, reducing the need to import each class manually. This functionality streamlines the process of utilizing numerous classes within a package and is particularly beneficial when dealing with extensive libraries. However, similar to BoxLang star-imports, it is essential to be aware of possible namespace conflicts and ensure that unintended classes do not get imported, maintaining code clarity and preventing ambiguity.

    Ability to import/create BoxLang classes from modules via direct `@{moduleName}` notation.

    The @ notation in BoxLang’s import system allows for more efficient and precise class referencing. By explicitly addressing classes from a specific module, performance is improved because it avoids the need for BoxLang to search through all available modules, reducing ambiguity in cases where classes with the same name exist in different modules. The module’s root serves as the base for addressing the class.

    Here’s a breakdown of how it works:

    By using this method, developers can avoid potential issues like performance degradation due to unnecessary module scanning and the possibility of naming conflicts. It provides a clear and concise way to manage dependencies and class imports in BoxLang.

    Ability to import create java classes from modules explicitly using the `@`notation

    Just like with BoxLang classes, you can also do the same for all Java libraries modules are packaged with. This allows you to import and create Java classes from specific modules by addressing them using the @ notation.

    The following were support tickets for all of these functionalities

    • Import Definitions now support module addressing for simple, wildcard and aliases

    • JavaResolver module targeted resolution

    MIgrate AST Capture to it's own experimental flag

    If you want to capture AST JSON for debugging purposes you will need to activate the new AST experimental flag:

    Add STOMP subprotocols in miniserver

    We continue to make great strides with easy websocket support for BoxLang. Now we have added our very own STOMP implementation which makes our websockets behave like AMQP Messaging Brokers like RabbitMQ.

    Improvements

    Move CFID to compat module

    Have servlet runtime return actual pagecontext object instead of fake

    Update the allowedFileOperationExtensions and disallowedFileOperationExtensions to the security block

    Allow casting to array of primitive types

    Improve exception when trying to invoke null as a function

    Get ColdBox Loading via ASM

    Improve logic surrounding loading of pre-compiled source files

    added a `isCommitted()` to the PageContext to match the servlet response to assist when doing resets without exceptions

    StopGaps and config from cfconfig.json to boxlang.json

    NotImplemented updated to check if it's a string and if empty, then ignore it to provide leeway

    Rename default sessions cache to `bxSessions` to create the `bx` prefix standards. Add configuration to boxlang.json

    Bug

    boxlang invokes private onApplicationStart

    expandPath does not preserve file system case

    cfml2wddx action missing

    deserializeJSON not handling white space / control characters

    Update parser to allow for `@module` notations on imports and `new` operators

    listFind() and listFindNoCase() are allowing partial matches

    Can't dump null in console

    Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null

    1.0.0-RC.1

    February 18, 2025

    🚀 BoxLang Release Candidate 1 is Here! 🚀

    After nearly a year of relentless iteration, rigorous testing, blood, sweat, lots of praying, tears, and over 1,000 resolved tickets, we proudly announce the first Release Candidate (RC1) of BoxLang! With 27 beta versions behind us, we are now on the final stretch toward the official 1.0 release.

    This milestone ensures that most of our libraries are fully compatible and certified for BoxLang, making it production-ready. RC1 delivers significant bug fixes, performance optimizations, and stability enhancements, enabling teams to deploy and fine-tune their applications in real-world environments confidently. We strongly encourage the community to start running production workloads now—your feedback will be instrumental in refining BoxLang ahead of the final release.

    Licenses Available TODAY!

    Additionally, we are thrilled to open up support license subscriptions () for BoxLang +/++, offering enterprise-grade support, priority fixes, and exclusive benefits. As an introductory offer, all licenses are available at 50% off for February. In March, with the release of RC2, discounts will adjust to 25% off—scaling down progressively until our official launch at Into The Box 2025 ().

    Let me also remind you that our Visionary Licenses will cease to be offered by the end of this month. Visionary licenses are unique for 10 years and 5 years of support. If you are interested in securing a visionary license, please email us at .

    Production Tips

    We encourage you to pre-compile your applications using our BoxLang compiler for incredibly safe and high-performance deployments since no parsing is involved. Combined with our new , your applications will fly and be highly performant.

    Release Notes

    New Features

    Make sure execution exceptions are propagated to an `exception.log` for all runtimes

    Create getHTTPTimeString bif in the CFML Compat Module

    Missing bif: createTime()

    Improvement

    returns 500 status code when hitting the default error page

    Allow annotation values of unquoted strings

    allow RHS of castas operator to omit quotes

    default output to true in Application classes

    Disable external DTD validation

    Migrate usage of LoggerFactory.getLogger to the internal BoxLang logger classes in the core

    BIF and Component abstract objects now have a logger that maps to a `runtime` logger for ease of use

    Favor native java methods on a struct if there is a key of that name, but it's not a function

    Improve boxpiler selection by using the interface not classes or direct implementations

    Bugs

    Abort should not fire the `onRequestEnd` method ( or it should fail quietly )

    Struct.put Usage Throws Error

    BX-ORM: When First Request to Application is a CFC, the application scope is undefined when starting ORMApp attempts to instantiate

    numeric key access of struct failing for BigDecimal keys

    directoryList does not sort by name

    Too many pattern letters: m

    Trivial: Typo in error message

    thread attribute scope needs to be headlessly accessible

    structget() incorrectly returning true with cfml-compat installed

    String caster doesn't work on char[] and produces incorrect results for Character[]

    class dump template doesn't work with compat module

    Access and mutation of native Java unboxed arrays doesn't work

    Query objects do not allow complex data when adding columns via `queryAddColumn()` with no data type.

    Can't use EMail as a returntype from EMail object

    shebang detection not working and skipping execution to the REPL

    isValid uuid returns false

    Error executing dump template

    default string representation of exception object

    Dereferencing property on Java class not calling getter

    Jakarta servlet removed response.setStatus( int, String ) from API

    Typo in exception string for parseDateTime

    getDirectoryFromPath breaks when passed a null value

    Durations created by `createTimespan` can't be casted to strings

    `this` scope can no longer be mutated

    final access modifier with explicit static scope on assignment not working

    static method access on non-imported identifer not working

    boxpiler was defaulting to javaboxpiler internally, remove it, it should be null and seeded later

    isSimpleValue returns true on Exception in Compat Mode

    QueryParam: SQL Server Unknown Column Type `datetime`

    ParseDateTime failure with `hh:nn a` mask - e.g. `03:00 PM`

    onRequestEnd() not firing for on class requests

    1.0.0

    May 1, 2025

    This was our first stable release of the BoxLang language. It grouped the entire betas and release candidate features and fixes. This specific version included the following release notes from issues that changed between release candidate 3.

    New Features

    Create the config `runtimes` struct so any runtime can store their settings there by convention

    Add simple rewrites to miniserver

    1.0.0-Beta23

    November 23, 2024

    Introducing BoxLang 1.0.0 Beta 23

    The latest release of BoxLang, Beta 23, marks a significant step forward in our journey to create the ultimate dynamic language for the JVM. Packed with powerful new features, important bug fixes, and thoughtful optimizations, this update is designed to make your development experience smoother, faster, and more reliable, especially after now starting to take 100s of comments and bug reports from our community.

    Modularity takes center stage in this release with the ability to define BoxLang components (aka Tags) within modules and a new version-checking mechanism that ensures module compatibility. Database interactions are now more intuitive with enhancements to the Generic JDBC Driver, and the introduction of the getSemver() function brings a robust tool for managing semantic versioning with precision and ease.

    1.0.0-Beta3

    June 28, 2024

    BoxLang Betas are released weekly. This is our third beta marker. Here are the release notes.

    New Features

    Implement query cache ability

    1.0.0-Beta14

    September 13, 2024

    In this release, we are excited to introduce several new features and enhancements aimed at improving functionality and user experience. These updates include the creation of Unmodifiable query types, new server keys to aid on CLI tooling, and methods to identify runtime initiation modes.

    Additionally, we've added an event announcement for dump rendering to enable better integration with external listeners. Read on to learn more about these features and how they can benefit your workflow.

    Code Strong!

    New Features

    BoxLangOrtus Solutions Community
    Improvements

    BL-1199 Add a `version` key to the boxlang.json to track the current version of the runtime.

    BL-1275 expandPath(".") when running boxlang as a shell script does not point to the current working directory

    BL-1278 Possible minor bug in Mail

    BL-1285 Can we improve URL to PDF support?

    BL-1286 Pre-compiled matchers for exception stack builds for performance

    BL-1287 LineNumber alias on exception traces for multiple Box tools in the open

    BL-1293 Upate isObject, isArray and IsStruct to have more edge cases and consistencies across engines

    BL-1296 looping over XMLNode as collection only loops over child nodes

    BL-1310 BoxLang file with no extension should try to determine if it's an executable class

    BL-1311 Expand relative this.mappings in application class

    BL-1323 change extract() BIF so filter argument works the same as directoryList()

    BL-1324 make missing template error use relative path, not absolute path

    BL-1334 Support samesite and expires in servlet

    BL-1336 change compress() BIF so filter argument works the same as directoryList()

    BL-1337 generatePBKDFKey() compat issues

    BL-1339 SCryptVerify() doesn't support hashes generated in Adobe ColdFusion

    Bugs

    BL-1098 Compat: FileMove in ACF/Lucee automatically overwrites the destination file

    BL-1123 Use of compat-transpiled name in scoped variable throws error

    BL-1131 Compat: Error parsing date with zero month

    BL-1218 Cookie with Quoted Value Intermittently comes back with URL-Escaped quotes

    BL-1266 Rethrown Exception Inside Transaction Being Wrapped In Application Exception

    BL-1267 Elvis using nullValue on right hand side throws error

    BL-1271 Using BIFS in CLI schedulers throws an error that request context is empty

    BL-1272 Dumping class with top argument results in Struct template error.

    BL-1273 Class which implements IReferenceable alone throws errors when Attempting Serialize to JSON

    BL-1274 Error with parseDateTime on ISO with fully numeric offset

    BL-1279 relative include with ../../ can result in illegal class name

    BL-1280 caches set operations relies on timeouts being Objects, do stricter validation and conversion to avoid can't cast string to longs

    BL-1281 hash CFML compatability

    BL-1282 cfml compat: returnformat is case sensitive for remote methods

    BL-1283 cfml compat - cfinclude with non cfml files

    BL-1284 CFML compat. Undefined query values are strings in ACF / Lucee

    BL-1289 CacheLocator cache is too aggressive on same name but different location classes

    BL-1290 dump templates for Function, Map and XML missing expand null checks

    BL-1291 XML structkeyExists returns false when objects are there but isNull returns false

    BL-1292 jsonSerialize() or deserialize with cookie setting is adding extra "

    BL-1294 static initializer above properties is giving a syntax error

    BL-1297 Update session storage key removal interceptor so it can detect if the clear is a session or not, as it could be in a cache that holds much more data

    BL-1299 Serializing queries to JSON compatibility

    BL-1301 DynamicObject.hasMethodNoCase() is returning false for methods that clearly exist and are invokable

    BL-1302 JDBC - Missing support for no connection limit

    BL-1303 Static access is not a valid construct for array access

    BL-1304 featureAudit incorrectly reports the valueList() BIF as missing

    BL-1306 cfhtmlhead does not work properly

    BL-1307 Implement CFCookie Expires

    BL-1308 cfcookie samesite attribute not honored

    BL-1309 CFML Compat - cfcookie encodevalue attribute not honored

    BL-1312 overriding `/` mapping in this.mappings not working

    BL-1313 dump/abort doesn't always default response content type in servlet

    BL-1317 ASM Boxpiler is not generating the correct bytecode when dealing with abstract classes

    BL-1321 bx:location throws error in console

    BL-1325 BX-PDF - Issue with PDF support and document section, specifically Acrobat Reader

    BL-1326 documentsection name not properly setting bookmark name

    BL-1328 Relax default permissions of bx:document

    BL-1331 Compat: dateTimeFormat "h" mask

    BL-1340 SCryptVerify() function aliases

    BL-1341 hash() returns lower case from CFM pages

    BL-1343 Schedulers defined in Application.bx do not have access to application scope values defined in onApplicationStart

    BL-1345 cliread was closing the system.in instead of sharing across the cli

    BL-1346 bitwise complement doesn't work with variable

    BL-1348 Expansion of "/tmp" resolves to relative path.

    BL-1349 elvis doesn't work in lambda

    Tasks

    BL-179 TimeBox Certification

    BL-1136 Compat: Document DateAdd Behavior with Decimal Number Difference from ACF/Lucee

    BL-1319
    BL-1327
    Debugging and performance have also seen major improvements. The dump function now outputs directly to the console in scripting contexts, simplifying debugging workflows, while significant optimizations in functions like len() and the DateTimeCaster improve execution speed and efficiency. We've also addressed critical issues around argument handling, JDBC URL creation, and logging performance, ensuring a more stable and predictable environment for your applications.

    Please continue to test your applications as we continue to push forwards towards stable release this winter.

    🚀 New Features

    1. Component in BX for Modules (BL-750) Modules in BoxLang just got a serious upgrade! You can now build components for BoxLang using BoxLang. No more Java ma!

    1. Module Compatibility Check (BL-768) The ModuleService now includes a powerful compatibility check for the "boxlang" version in your box.json. This ensures that your modules are running on a supported version of BoxLang, avoiding unexpected runtime issues. Just add the minimumVersion to the box.json under the boxlang section and it will tell the Module Service which supported minimum version your module will work on.

    1. Generic JDBC Driver Enhancement (BL-771) We've added a default URL delimiter to the Generic JDBC Driver. This improvement makes BoxLang more adaptable to various database configurations, simplifying JDBC URL handling for databases with unique delimiter requirements.

    2. New getSemver() BIF (BL-777) Introducing the getSemver() built-in function! You can now quickly parse or construct semantic versioning (semver) strings and work with them as Semver objects for enhanced version management. The new BIF will parse and give you a Semver object to work with. You can also use it to build fluent semantic version strings.


    🔧 Improvements

    • Console Output for dump in Scripting Contexts (BL-769) Debugging just got easier! By default, the dump function now outputs to the console when running in scripting contexts, making it seamless to debug CLI scripts.

    • Optimized len() Function (BL-770) The len() function is now smarter and faster! We've removed unnecessary date parsing, resulting in better performance.


    🛠️ Tasks

    • Query Options Completion (BL-116) We've implemented unfinished query options, giving you more control and flexibility when working with data queries.


    🐞 Bug Fixes

    1. abort in cfdump Tag (BL-761) Resolved an issue where using abort in conjunction with the cfdump tag caused unexpected errors.

    2. Whitespace Handling in HTTP Responses (BL-763) Improved handling of whitespace in responses where the Content-Type header was not yet set, ensuring better compatibility with various HTTP clients.

    3. Positional vs Named Arguments (BL-765) Fixed inconsistent behavior when handling arguments passed by position versus named.

    4. Invalid JDBC URLs (BL-772) Corrected the handling of the dsn key for JDBC drivers, ensuring compatibility with cfconfig replacements and producing valid JDBC URLs.

    5. Improved DateTime Performance (BL-774) Enhanced the performance of the DateTimeCaster and DateTime object instantiation when working with strings.

    6. Endless Recursion in onSessionStart() (BL-775) Addressed an issue where the onSessionStart() event could cause infinite recursion under certain conditions.

    7. debugmode in boxlang.json (BL-776) Fixed a problem where the debugmode flag was not being utilized as expected.

    8. Servlet Debug Mode Reconfiguration (BL-778) Resolved issues with reconfiguring debug mode in servlet-based environments.

    9. Logging Performance (BL-779) Overhauled the LoggingInterceptor to prevent inefficient recreation of appenders and loggers, especially under heavy stress.

    10. Missing application Argument in Logging (BL-780) The writelog and log components now properly support the application boolean argument.


    Why Upgrade?

    This release has powerful new features, performance enhancements, and critical bug fixes. Whether you're a developer building complex applications or managing modular systems, Beta 23 makes your BoxLang experience smoother and more efficient.

    Ready to dive in? 🚀 Update to Beta 23 now and take your BoxLang projects to the next level!

    BL-542 BoxRunner cli options are now prefixed with `--bx-{option}`

    This is a breaking change in our betas. All the CLI options for the BoxRunner now use the --bx- prefix. We are doing this to avoid any issues going forward when building CLI tooling. Pleaes checkout the Running Boxlang section for all the docs on this.

    BL-93 Create Unmodifiable query type

    We have now introduced the Unmodifiable query type. Any query in BoxLang can become Unmodifiable by just calling the toUnmodifiable() method on it. This will lock the query into read-only mode. Great for multi-threaded operations or just data safety. You can also unlock Unmodifiable types via the toMutable() method.

    BL-529 Announce the onBXDump whenever a dump is about to be rendered, to allow for external listeners to receive the dump

    We have added a new global listener for the language: onBxDump which allows you to listen to any call to our dump component. This will allow developers to tap into the dumping facilities and intercept the dump calls. We are doing this in order to bring real-time dump facilities to VSCode.

    All the arguments from the dump bif/component will be passed through.

    BL-538 New runtime inCLIMode() method to tell you if the runtime was started via the runtime or something else

    This is a new method in the BoxRuntime which allows developers or module authors to know if your runtime is in CLI mode or not. The server.boxlang also contains much more information about the modes you are in:

    • server.boxlang.cliMode - True or false if you are in CLI mode

    • server.boxlang.jarMode - True or false if running in JAR mode

    • server.boxlang.runtimeHome - The runtime home seeded in the runtime

    BL-539 New server.cli key to provide you with all the CLI options used to run the runtime

    There is a new server.cli structure that will assist CLI developers. It contains the following data:

    • server.cli.executionPath - From what directory was the runtime command called from

    • server.cli.command - The full raw commandline string used by the OS to call the binary + your command

    • server.cli.args - The raw array of arguments the command was called with

    • server.cli.parsed.options - A struct of name-value pairs of all the options detected in the CLI arguments.

    • server.cli.parsed.positionals - An array of positional arguments sent to the CLI

    BoxLang will detect and parse the following conditions into the options struct:

    • --{name} - Will crete a key called {name} with a value of true

    • --!{name} - Will crete a key called {name} with a value of false

    • --no-{name} - Will crete a key called {name} with a value of false

    • -{character} - Shorthands using a single character. The value will be true and the key will be the character used. Example: -p

    • -{characters} - You can use multi-shorthand characters and each of them will be keys in the struct with a value of true. Example: -abc will create a=true, b=true, c=true

    • --{name}=value - Will create a key called {name} with the value from the right side of the equals sign.

    • --{name}="value" - Will create a key called {name} with the value from the right side of the equals sign and removing the quotes.

    • --{name}='value' - Will create a key called {name} with the value from the right side of the equals sign and removing the single quotes

    BL-540 Refactor the CLIOptions to it's own class and add a simple argument parser

    In preparation to the inclusion of CommandBox commands into BoxLang we have also added our CLI utility to assist with argument parsing and detection. We have also encapsulated our CLI tooling in preparation for more in the next betas.

    Improvements

    BL-228 Consolidate/Rename "LS" Bifs and Move US-Centric ones to Compat

    BL-409 Member method cleanup

    BL-410 Improve REPL output of native Java arrays

    BL-541 Add "decimal" as a cast type

    Bugs

    BL-496 replace and replaceNoCase functions do not accept a callback

    BL-519 Query dereferencing is not working correctly: Column '1' does not exist in query

    BL-520 Run Class via URL

    BL-523 A class which uses inheritance, the metadata includes the inherited functions in itself and parent.

    BL-524 reFindNoCase( "^(f|x)?test$", arguments.methodName ) fails with Cannot invoke "String.length()" because the return value of "java.util.regex.Matcher.group(int)" is null

    BL-525 lsParseDateTime errors when given locale and mask

    BL-526 dateformat incorrectly parsing date with leading 0's?

    BL-527 onMissingMethod is not firing if the execution of the method is from within the class

    BL-528 query dumps assume the value is simple and can explode with encodeForHTML() can't do complex objects

    BL-530 Improve tracking of class in function box context

    BL-531 Difference of behavior with cfdirectory recurse = true not including path

    BL-532 super long strings cause compilation errors due to limitations in Java source code

    BL-533 Errors in miniserver when flushing large amounts of output to buffer

    BL-534 Missing !== operator

    BL-535 query cell assign erroring

    BL-537 Add onBifInvocation Interception Announcement to BIF invoke method

    /**
     * This is a BoxLang only Component
     *
     * Annotations you can use on a component:
     * <pre>
     * // The alias of the Component, defaults to the name of the Class
     * @BoxComponent 'myComponentAlias'
     * @BoxComponent [ 'myComponentAlias', 'anotherAlias' ]
     * @AllowsBody [boolean=false]
     * @RequiresBody [boolean=false]
     * </pre>
     *
     * The runtime injects the following into the variables	scope:
     * - boxRuntime : BoxLangRuntime
     * - log : A logger
     * - functionService : The BoxLang FunctionService
     * - interceptorService : The BoxLang InterceptorService
     * - moduleRecord : The ModuleRecord instance
     *
     * The runtime also injects the following helpers into the variables scope:
     * - newBuffer() : Create and return a new StringBuffer
     * - newBuilder() : Create and return a new StringBuilder
     * - processBody( context, body, [buffer] ) : Process the body of a component
     * - getName() : Get the name of the component
     */
    @BoxComponent 'HolaComponent'
    @AllowsBody true
    @RequiresBody false
    class{
    
    	/**
    	 * The execution of this Component
    	 *
    	 * <pre>
    	 * <bx:holaComponent>This is my output</bx:holaComponent>
    	 * </pre>
    	 *
    	 * @param context The context of the execution (IBoxContext)
    	 * @param attributes The attributes of the component that were passed in
    	 * @param body The body of the component that you can pass to `processBody(context, body, [buffer])` for execution and buffer retreival
    	 * @param executionState The execution state of the component. Each component get's one as an isolated state.
    	 *
    	 * @return A BodyResult instance or null for a default result return.
    	 */
    	function invoke( required context, Struct attributes, any body, Struct executionState ){
    		// A buffer to capture the body output
    		var	buffer		= newBuffer();
    		var	bodyResult	= processBody( context, body, buffer );
    
    		// // If there was a return statement inside our body, we early exit now
    		if ( bodyResult.isEarlyExit() ) {
    			return bodyResult;
    		}
    		// // reverse the buffer contents and place into a string
    		var newContent	= buffer.reverse().toString();
    		// // output it to the page buffer
    		context.writeToBuffer( newContent );
    	}
    
    }
    "boxlang": {
        "minimumVersion": "1.0.0",
        "moduleName": "test",
    }
    var version = GetSemver( "1.2.3-alpha+20151212" )
    var version = GetSemver( "1.2.3-alpha" )
    var version = GetSemver( "1.2.3" )
    var version = GetSemver( "1.2.3+20151212" )
    var version = GetSemver( "1.2.3-alpha.1" )
    var version = GetSemver( "1.2.3-alpha.beta" )
    
    var version1 = GetSemver( "1.2.3" )
    var version2 = GetSemver( "1.2.4" )
    var version3 = GetSemver( "1.3.0" )
    
    version1.compare( version2 ); // -1
    version1.compare( version3 ); // -1
    version2.compare( version3 ); // -1
    
    var version = GetSemver().withMajor( 1 ).withMinor( 2 ).withPatch( 3 ).withPreRelease( "alpha" ).toSemver()
    var versionString = GetSemver().withMajor( 1 ).withMinor( 2 ).withPatch( 3 ).withPreRelease( "alpha" ).toString()
    // Just call the toUnmodifiable() to lock the type
    myData = myDataService.queryData().toUnmodifiable()
    
    // You can also unlock it via the toMutable() method
    unlockedData = myData.toMutable()
    function onBxDump( data ){
      .. listen to the dump call
    }
    Thanks to our enterprise cache engine and aggregator built into BoxLang, you can now use it to cache queries via its options configuration structure using cfquery or queryExecute. Here are the query caching properties you can use:
    • cache:boolean - To turn on caching, this must be true. The default is false

    • cacheTimeout:timespan - Optional timeout of the query in the cache. By default, is uses whatever the default timeout of items the cache has been configured with.

    • cacheLastAcccessTimeout:timespan - Optional last access or idle timeout of the query in the cache. By default, is uses whatever the default timeout of items the cache has been configured with. This means that if this query is NOT used or requested in this timespan, it will be marked for eviction.

    • cacheProvider:string - The name of the cache provider to store the queries. By default, we use the DEFAULT cache in BoxLang.

    By default, queries will use the default Boxlang CacheProvider, which has default timeouts and lastAccessTimeout values set.

    To specify a custom caching provider, you can use the cacheProvider query option:

    To specify custom cache entry timeouts, use cacheTimeout or cacheLastAccessTimeout:

    Note that the bx-compat-cfml module will take care of implementing the historical cachedWithin and cachedAfter query options.

    Metadata

    All query metadata will also have the cache information available to you as well. So you if get dump the query metadata you will see a ton of debugging information about the query:

    Interacting With The Cache

    Please note that this leverages the BoxLang cache. This means you have full access to the cache provider and you can interrogate it for queries, clear all of them, or clear one of them. The default prefix used for all cached queries is: BL_QUERY

    BL-261 coerce java SAMs from BoxLang function interfaces

    This is another major milestone in the Java interop features of BoxLang. This allows us to coerce any BoxLang Lambda/Closure/UDF or even Classes to ANY, yes, ANY Java Functional Interface or Java SAM (Single Abstract Method Interface).

    BL-281 AsyncService support for Virtual Thread Executors (create/manage)

    Virtual Threads are now available to BoxLang via executors. You can choose the new VIRTUAL executor for schedulers or when creating schedulers via our AsyncService. This will treat all tasks and schedules to use virtual threads.

    More entry points to access this executor will be provided in the coming betas, alongside our very own runAsync() and the ability to create virtual threads as well.

    BL-284 Bifs for module info: getModuleList() getModuleInfo( module )

    As more modules are being developed for BoxLang, you now have the ability to know which modules have been loaded and activated in the language. As well as specific information about a module if needed. This is great for inter-dependencies and checking if modules have loaded from BoxLang.

    BL-285 Dumping of Java Classes now includes a dump of the `toString()` value to visualize values better

    This is a developer eye-candy, so when you dump any Java class, you can actually see the value of the class instance data via the toString() method.

    BL-289 New dump template for BL Functions

    The dumping of BoxLang Functions (Closures, Lambdas, UDFs), either standalone or from a class, has great visibility now. You can see even the class used to generate the function, the function annotations, and much more.

    BL-292 Allow the createDynamicProxy bif to support the request class loader so it can load classes from loaded libraries in the application.bx, runtime and more.

    If you use createDynamicProxy() to make a BoxLang class look like a Java class, you can continue to do so now, but it accounts for all class loaders in the application. If you come from a CFML engine, this is impossible and is always a pain and limitation.

    In BoxLang, your context matters. So depending on where you create the dynamic proxy, it will account for the surrounding class loaders to be able to create the appropriate Java proxies.

    BL-298 New Script Binaries for bxCFTranspiler, bxCompiler, bxFeatureAudit tools in the distribution bin folder

    We have introduced Windows and Mac/Linux binaries for running several CLI tools. You no longer need to refer to the docs with extra-long options. You can now use the provided binaries to call the appropriate CLI tool.

    If you use the quick installer, all these binaries will be installed for you.

    Improvements

    BL-254 Refactor JDBC connection retrieval out of the QueryOptions class

    BL-280 Dynamic method matching discovery algorithms updated to do 2 pass algorithm: exact, loose coercion matching

    BL-283 Improvement of cache service and cache provider methods for easier boxlang interactions

    BL-290 Refactored the dump css to `resources/dump/html/Dump.css`

    BL-291 Migrate dynamic proxies to native java implementation from the JDK

    BL-296 passing the session id to the onsessionstart listener

    BL-297 Give better warnings if the sessionStorage is not a valid string

    Bug

    BL-198 attributecollection not handled properly on cfthrow

    BL-278 Left in system out calls that need to be removed

    BL-279 JSR ScriptEngine starting runtime without debug flag if passed

    BL-282 Creating a default cache was not setting the right name and a "default" already registered exception was being thrown

    BL-286 Default argument values not always checked for type

    BL-287 Implements missing from Box Class metadata

    BL-288 Static Scope missing from metadata

    BL-256
    BL-667
    BL-232
    BL-653
    BL-653
    BL-646
    BL-647
    BL-648
    BL-657
    BL-658
    BL-612
    https://community.ortussolutions.com/t/introducing-the-socketbox-stomp-broker-demo/10396
    BL-328
    BL-637
    BL-644
    BL-650
    BL-652
    BL-654
    BL-655
    BL-660
    BL-661
    BL-662
    BL-666
    BL-635
    BL-636
    BL-639
    BL-642
    BL-645
    BL-649
    BL-651
    BL-659
    https://www.boxlang.io/plans
    www.intothebox.org
    [email protected]
    trusted cache settings
    BL-1065
    BL-1070
    BL-1071
    BL-1020
    BL-1027
    BL-1028
    BL-1029
    BL-1034
    BL-1050
    BL-1052
    BL-1054
    BL-1062
    BL-816
    BL-1008
    BL-1023
    BL-1025
    BL-1030
    BL-1031
    BL-1032
    BL-1033
    BL-1035
    BL-1037
    BL-1038
    BL-1039
    BL-1040
    BL-1041
    BL-1043
    BL-1044
    BL-1045
    BL-1047
    BL-1048
    BL-1049
    BL-1051
    BL-1053
    BL-1055
    BL-1058
    BL-1059
    BL-1060
    BL-1061
    BL-1066
    BL-1068
    BL-1069
    BL-1075
    Planswww.boxlang.io
    www.boxlang.io/plans

    1.0.0-Beta10

    August 16, 2024

    BoxLang Betas are released weekly. This is our tenth marker and we are incredibly excited to bring you a very big release. This gives us a huge push forwards towards compatibility with other engines and many more new features we have always wanted in our language. Enjoy!

    Release notes - BoxLang - 1.0.0-Beta10

    New Features

    transpile queryGetRow() to queryRowData()

    Ths is a compatibility feature for CFML engines so they can use the queryGetRow() BIF which internally funnels to the () method.

    Ini files support

    CFML engines always had half baked support for working with INI files. We now have full support and a fluent way to interact with ini files. This is really important for those building IoT solutions or interacting with micro processor devices. To get started use the boxlang installer install-bx-module bx-ini or if using CommandBox: install bx-ini

    Here is a typical ini file example:

    Here are the contributed functions in this module:

    • getIniFile( file ) : Reads an ini file and returns the IniFile object. If the file does not exist, it will create it.

    • getProfileSection( iniFile, section ) : Gets a section from the ini file as a struct

    • getProfileSections( iniFile ) : Gets all the sections from the ini file as a struct of structs

    The IniFile object is a fluent object that allows you to work with ini files in a very easy way. Here is an example of how to use it:

    JSStringFormat BIF

    This BIF is now complete to provide JavaScript escaping when using BoxLang as the template processor:

    xml component

    We have now finalized XML support in BoxLang with a beautiful xml component:

    getVariable() & setVariable()

    These two functions now exist in the compat module. It allows you to set and get variables in the variables scope. This can also be used to retrieve dynamic variable names or set dynamic variable names:

    Add getClientVariablesList() to compat

    Legacy client scope support added to the compat module

    New getDescendantsOfType() AST method with predicate

    This is an internal method of our contexts to allow us to retrieve things easily with predicates.

    Implement single quote escapes in queries and preserveSingleQuotes

    We thought this was going to be an easy one. preserveSingleQuotes() is now built for the core language to assist when building dynamic SQL and escaping quotes smartly.

    Allow .cfm and .cfs files from the boxlang CLI runner

    Our BoxLang runner now allows for the CLI execution of cfm and cfs files directly along side BoxLang templates.

    Add isNumericDate BIF

    This BIF is now in the core thanks to a client migration.

    Add getHTTPTimeString BIF to web-support

    Our web support package gets a new BIF thanks to a client migration

    Writedump label support

    WriteDump in BoxLang now get beautiful labels!

    java.math.BigInteger caster

    We have a new caster for BigInteger and BigDecimal to help us with precise mathematics in BoxLang.

    Improvements

    When doing class serialization make sure to identify which properties have `serialize=false` on them

    Our serializer to binary for classes now respects the serialize annotation on properties.

    content component can have body

    Enhance error messages for parsing invalid tag code

    Bugs

    MalformedInputException: Input length = 1 when parsing CFC

    component detection can be tricked if there is a tag comment line starting with the word "component"

    Regression: Can't run files via BoxRunner due to new action command logic

    Sometimes trying to shutdown runtime throws NPE if it was never started fully

    pretty print visitor outputting extra " on tag catch block

    pretty print visitor doesn't handle array notation invocation

    1.0.0-Beta27

    January 31, 2025

    This release brings enhanced XML handling, new CLI app support, improved error handling, and expanded interoperability with Java and CFML runtimes. We've also added new HTTP event hooks, improved caching strategies, and a streamlined class resolution process to make your applications more performant, even in debug modes.

    🌟 Highlights:

    ✅ Enhanced XML Support – Improved cloning, merging, and namespace handling in XML operations. ✅ Unified Template & Script Grammars – BoxLang now seamlessly integrates both styles, bringing performance updates to the parser. ✅ Improved Java Interop – Automatic coercion of BoxLang arrays to native Java arrays and varargs support ✅ Better Error Handling – More robust dump rendering and exception management. ✅ New CLI Features – Built-in functions like cliRead(), cliGetArgs(), and cliExit() for pure CLI apps. ✅ Improved HTTP Handling – Proxy support, authentication, and new request/response events.

    ✅ Trusted Cache – Trusted cache is in the house, to get high performance in production

    ✅ Class location caches – More performance updates for class resolutions for BoxLang classes

    With over 40 improvements, new features, and fixes, this release makes BoxLang even more powerful and stable! 🔥

    Improvements

    Implement Node pass-through methods to handle cloning and merging of XML objects

    Combine template and script grammars for boxlang

    Error Getting method keyExists for class ortus.boxlang.runtime.types.XML

    StructFindKey returns two findings on the same node if top level key is array

    Better error handling when dump template errors

    Return callback return value from runThreadInContext()

    java interop coerce BL arrays to native arrays

    Add toOptional() method to Attempt

    coerce return values of proxied methods

    output class of non-simple valued fields in class output for cfdump

    prefer same mapping for relative class lookups in box resolver

    Client scope needs more consistencies like the session scope when validating and expiration determination

    Module service record was not registering interceptors with the module settings

    HTTP Component - Implement Proxy Server handling

    add default itnerface helper for the IBoxContext to get the running application name if any

    Servlet to support Jakarta namespace

    New Features

    Move defaultCache to the caches section as default, verify it exists, else create it anyways

    add http events: onHTTPRequest, onHTTPResponse

    Expose buildRegistry() and encapsulate per location registration

    CLI BIFS for working with pure cli apps: cliRead(), cliGetArgs(), cliExit()

    Activate box resolvers cache according to request and app settings

    New setting: classResolverCache : boolean [true] which controls if the class locators caches resolve lookups

    Bugs

    varargs not working

    CF casts Class instances to a String

    Namespaced XML nodes not accessible by their non-namespaced names

    XMLSearch Not Finding Correct Results When Namespaces are Present

    XML asString Generates trailing line break

    StructFindKey Not Returning owner values correctly

    ASM compilation error

    query with empty column name can't be dumped

    WriteDump()/Dump() is broken in current snapshot build

    DateCompare on two zero-hour strings fails with long overflow

    XMLElemNew Illegal Character exception when using the namespace URI as the second argument

    HTTP Component - Implement Basic Authentication

    Cannot access variables scope in a static context -- but there is no variables access

    timezone not always used in datetime caster

    toUnmodifiableStruct() method not threadsafe

    directoryList filter param does not accept a closure

    Support for guid and uuid type

    getDirectoryFromPath returns different result to Lucee and ACF

    argument type of binary is not supported

    argument type of email is not supported

    CGI scope reporting 0 items

    JSONSerialize pretty prints JSON which blows up outbound NDJSON

    CFHTTParam Encodes Query Strings By Default

    URLEncodedFormat Replaces Spaces with Plus Symbols

    Bracket Notation Usage on Java Hashmaps Does not work.

    Detail and Extended Info Can Be Null In Thrown Exceptions

    Planswww.boxlang.io
    https://www.youtube.com/live/Bn3gzjzjtuc?si=ahCHxXKqg7_CASkOwww.youtube.com

    1.0.0-Beta26

    January 14, 2025

    BoxLang Beta 26 Has Landed!

    We’re thrilled to announce the release of BoxLang 1.0.0 Beta 26, a monumental update that takes performance and functionality to the next level. This beta officially certifies the ColdBox HMVC Framework to run on BoxLang, marking a significant milestone in compatibility. Not only can you now run all ColdBox applications seamlessly on BoxLang, but with the latest ColdBox snapshot, you can also build your entire applications in BoxLang, unlocking the full potential of this dynamic and expressive language for modern application development.

    This release also introduces blazing-fast Query of Queries (QoQ) support, delivering speeds up to 70 times faster than Adobe or Lucee in specific scenarios, along with exciting new features like list parameter support in JDBC queries and custom QoQ functions. Over 70 bugs have been resolved, and significant improvements have been made, such as enhanced debugging capabilities, refined Box Script syntax, and robust session and metadata handling. With Beta 26, BoxLang continues to push the boundaries, empowering developers to build robust, efficient, and fully modern JVM-based applications.

    1.0.0-Beta11

    August 23, 2024

    We have really kicked into gear with this release, tackling a whopping 26 tickets and delivering some of our most aggressive features to date. This update signifies a significant leap forward towards a stable release in the Fall. Thank you for your continued support and stay tuned for more exciting developments!

    New Features

    queryExecute(
        "SELECT * FROM developers WHERE role = ?",
        [ "Developer" ],
        { cache: true }
    );
    queryExecute(
        "SELECT * FROM developers WHERE role = ?",
        [ "Developer" ],
        { cache: true, cacheProvider : "redis" }
    );
    queryExecute(
        "SELECT * FROM developers WHERE role = ?",
        [ "Developer" ],
        {
            cache: true,
            cacheTimeout : createTimespan( 0, 0, 0, 30 ),
            cacheLastAccessTimeout : createTimespan( 0, 0, 0, 30 )
        }
    );
    writedump( myQuery.$bx.meta )
    // Clear everything in the default cache
    getBoxCache()
        .clearAll()
    
    // Clear only the cached queries
    getBoxCache()
        .clearAll( key-> key.getName().startsWith( "BL_QUERY" ) )
    
    // Get a list of all cached queries
    getBoxCache()
        .getKeys( key-> key.getName().startsWith( "BL_QUERY" ) )
    
    // Get a stream of all the cached queries
    getBoxCache()
        .getKeysStream( key-> key.getName().startsWith( "BL_QUERY" ) )
    // Build your own Java comparators with BoxLang
    Collections.sort(
        myArray or Java Array,
        (s1, s2) -> compareNoCase( s1, s2 )
    )
    
    // Create your own threads and completable futures
    CompletableFuture.supplyAsync( () -> println( "Running in a thread" ) )
    
    // Java predicates
    arrayOfNumbers = [1,22,3,34,34,556]
    arrayOfNumbers.stream()
        .filter( n -> n % 2 == 0 )
        .toList()
    // Create, register and return
    getBoxRuntime().getAsyncService()
        .newVirtualExecutor( "MyVirtualExecutor" )
    writedump( getModuleList() )
    writeDump( getModuleInfo( "bx-image" ) )
    createDynamicProxy( myclass, [ array of interfaces ] )
    createDynamicProxy( myclass, interface path )
    // This is the experimental features flags.
    // Please see the documentation to see which flags are available
    "experimental": {
    	// This choose the compiler to use for the runtime
    	// Valid values are: "java", "asm"
    	"compiler": "java",
    	// If enabled, it will generate AST JSON data under the project's /grapher/data folder
    	"ASTCapture": false
    },
    import cbvalidation.models.*;
    import cbvalidation.models.result.*;
    
    class accessors="true" serialize="false" singleton {
    
        ...
        // cbvalidation.models.GenericObject
        target = new GenericObject( arguments.target )
        
        ...
    
    }
    // Star-import of all classes in the package
    import org.apache.commons.lang3.*;
    
    class{
        
        function main( args=[] ){
            // Using StringUtils from Apache Commons Lang
            var reversed = StringUtils.reverse("BoxLang");
            println("Reversed: " + reversed);
    
            // Using RandomStringUtils from Apache Commons Lang
            var randomString = RandomStringUtils.randomAlphanumeric(10);
            println("Random String: " + randomString);
        }
    }
    // Import from the cborm module
    import models.ActiveEntity@cborm
    target = new ActiveEntity()
    
    // Import from the cborm module using aliases
    import models.ActiveEntity@cborm as AC
    target = new AC()
    // Importing a specific class from the ESAPI Module
    import org.owasp.esapi.ESAPI@bx-esapi
    encoder = ESAPI.encoder()
    
    // Importing and aliasing a class from the ESAPI library
    import org.owasp.esapi.ESAPI@bx-esapi as SecurityAPI
    encoder = SecurityAPI.encoder()
    
    // Creating Java Classes
    encoder = new java:org.owasp.esapi.reference.DefaultEncoder@bx-esapi();
    
    // This is the experimental features flags.
    // Please see the documentation to see which flags are available
    "experimental": {
    	// This choose the compiler to use for the runtime
    	// Valid values are: "java", "asm"
    	"compiler": "java",
    	// If enabled, it will generate AST JSON data under the project's /grapher/data folder
    	"ASTCapture": true
    },

    Welcome to what could be our last beta before the final release of our initial 1.0.0 version of BoxLang and its multi-runtimes.

    New Features

    BL-94 Create query of queries support

    BL-883 Implement list parameters in JDBC queries

    BL-933 Ability to register custom functions for QoQ

    BL-942 Interceptor Service now does a service loader load of all interceptors found in the runtime to auto-load them

    Improvements

    BL-852 dump Lots of UI quality of life improvements: show length of strings, show full classes for some Java integrations, and much more.

    BL-860 Update getMetaadata() for dynamic proxies to leverage the class metadata instead of instances

    BL-865 CFTranspiler should not turn off accessors for persistent classes

    BL-866 Exception type matching check cause

    BL-919 Implement "Quick" algorithm for Hash BIF

    BL-920 Compat: CacheGet second argument is boolean for Lucee

    BL-926 ASM error in do/while with a break

    BL-938 Update the getOrCreateSession() to verify if the session has expired, and if so, rotate it.

    BL-939 Change generic tag-in-script syntax for Box Script to prefix with bx:

    Bugs

    BL-621 Allow a productivity hack to add ability to pass queries to some struct functions by taking the first row and converting the query to a struct.

    BL-732 structsort with callback errors

    BL-758 QofQ shouldn't require global DSN

    BL-764 xmlsearch - invalid XPath

    BL-801 ASM Failing test - fix bx:output transformer

    BL-802 ASM Failing test - fix abort exception

    BL-834 Dump Top Updates will not dump certain classes without a top argument, top shows as reached for subsequent dumps

    BL-847 BL GenericProxies cannot have java.lang.Object methods call on them

    BL-849 Class properties are merged from all inheritance levels in the metadata

    BL-850 Dumps are not in order of execution

    BL-851 Java List dumps are not working with top and are off by 1

    BL-854 Wirebox Block: testbuildJavaClass Methods on Java objects cannot be called with named arguments when using invoke()

    BL-855 Coercion for constructors from string to numbers are not working

    BL-856 Coercion from strings to numbers does not exist

    BL-857 isInstanceOf bif and keyword are not working on createObject("java") proxies. It gives a negative result

    BL-858 var scoping issues for bleeding scopes on class dump template

    BL-859 Calling getMetadata() on an instance of dynamic object that has not yet been inited, shows the metadata of DynamicObject instead of the proxy class

    BL-861 ORM: getter setters are not enabled for persistent CFCs

    BL-863 ORM: writedump causes ClassInfo not found

    BL-864 ORM: entityLoad should only require entity name

    BL-867 Show the right exception type when invoking dynamic objects and there are exceptions from a caused by

    BL-868 caching does not handle quoted numbers or booleans in config

    BL-869 ORM: EntityLoad errors when using a filter

    BL-870 soft reference cannot be stored directly in a struct

    BL-875 rework onSessionEnd to make sure the application exists when calling the listeners

    BL-877 Lucee allows params to be passed to cfquery tag via `params` attribute

    BL-879 IsNumeric() returns true for "true" and "false"

    BL-880 QueryNew() throws exception if row data array is empty

    BL-884 MSSQL throws error when executing certain queries if language is not English

    BL-885 Setting a dynamic variable name doesn't work

    BL-886 Can't cast [now] to a DateTime

    BL-887 cfloop step not implemented

    BL-888 allow "switch" as struct key name in CF script

    BL-889 The instance [ortus.boxlang.runtime.types.exceptions.ParseException] has no public field or inner class [ERRORCODE]

    BL-890 In function [numberFormat], argument [number] with a type of [java.lang.Boolean] does not match the declared type of [number]

    BL-891 Datasources created after module load take on custom DSN parameters defined in bx-mssql

    BL-892 cfqueryparam with list attribute causes "The index 2 is out of range"

    BL-893 Queryparam list=true is unsupported

    BL-894 Key in arguments scope gets lost

    BL-895 Allow "switch" to be used in dot access

    BL-896 Can't cast ts to a Number.

    BL-897 named query params not handled correctly

    BL-898 Account for placeholder text in comments and quoted strings in SQL

    BL-899 numberFormat is displaying a leading 0 when formatting integers < 10

    BL-901 Duplicate() on CGI scope creates empty struct

    BL-902 CGI-Scope weirdness

    BL-903 MSSQL connection gets lost

    BL-904 Empty test fails when using ASM

    BL-905 MSSQL Query columns have wrong values

    BL-906 Using bx:output inside of bx:catch causes bxCatch scope to disappear

    BL-907 Array Loop with negative step doesn't work

    BL-909 Cannot invoke "ortus.boxlang.runtime.components.Component$BodyResult.isEarlyExit()" because "bodyResult" is null

    BL-910 Passing query column to listToArray() BIF fails

    BL-911 IsNumeric BIF returns true on booleans in compat mode

    BL-912 getBaseTemplatePath returns `Application.cfc` in onRequestStart

    BL-913 Throw with exception object as unnamed argument fails

    BL-914 Null session scope when attempting to update the last visit

    BL-917 Compat GetComponentMetadata Failures with "Can't cast null to a Key".

    BL-918 String [1 LTE 5] cannot be cast to a boolean

    BL-923 Compat: Attributes to Functions Are Scoped in to nested Parameters Struct

    BL-925 Cannot invoke method [clearbuffer()] on a null object

    BL-927 Double variable assignment failing in ASM

    BL-928 Compat: Invoke method has different required object method

    BL-930 StructFindKey Returns a Null Value when Struct being searched contains nulls

    BL-932 toBinary() not lenient enough for decoding with line paddings

    BL-936 When doing named parameter queries and you send more parameters than required, it should ignore them, not throw an exception that you sent more

    BL-937 getOrCreateSession() relying on the starting listener for settings, when it should look at the context to reflect changes if any

    BL-941 WebRequest interceptor in web support is not auto-loading, also will affect any other composable runtimes

    BL-944 node.xmlText explicit assignment throws error that value is not node or XML instance

    BL-945 xmlAttributes assignment error - key not found

    Task

    BL-217 ColdBox Test Suite

    BL-220 Quick Test Suite

    BL-548 Parser performance and removing ambiguity

    BL-767 CFcasts Suite

    BL-837 UnleashSDK Certification

    BL-908 Incorporate TestBox test suite

    Stories

    BL-237 Phase II : Update all the toAST() methods to the new and consolidated approach

    BL-238 Phase III : Performance tests for phase I + II toolchains

    BL-239 Phase V : Create the QoQ SQL grammar, parser, and astss

    BL-953
    BL-955
    BL-956
    BL-958
    BL-959
    BL-964
    BL-966
    BL-967
    BL-968
    BL-983
    BL-984
    BL-998
    BL-999
    BL-1002
    BL-1010
    BL-1013
    BL-843
    BL-935
    BL-952
    BL-989
    BL-1009
    BL-1016
    BL-389
    BL-931
    BL-947
    BL-949
    BL-950
    BL-951
    BL-960
    BL-961
    BL-965
    BL-969
    BL-970
    BL-977
    BL-978
    BL-981
    BL-982
    BL-985
    BL-991
    BL-994
    BL-995
    BL-996
    BL-1000
    BL-1003
    BL-1004
    BL-1005
    BL-1015
    BL-1017
    Logo
    Logo
    Logo

    getProfileString( iniFile, section, entry ) : Gets an entry from a section in the ini file, if it does not exist, it will return an empty string

  • setProfileString( iniFile, section, entry, value ) : Sets an entry in a section in the ini file, if the section does not exist, it will create it

  • removeProfileSection( iniFile, section ) : Removes a section from the ini file

  • removeProfileString( iniFile, section, entry ) : Removes an entry from a section in the ini file

  • BL-435
    queryRowData
    BL-436
    BL-437
    BL-439
    BL-442
    BL-443
    BL-444
    BL-448
    BL-449
    BL-450
    BL-440
    BL-441
    BL-143
    BL-447
    BL-425
    BL-426
    BL-429
    BL-427
    BL-428
    BL-432
    BL-451
    BL-452
    BL-453
    BL-236 Phase I : Performance improvements for grammar and parser validation

    We have been working with an amazing ANTLR expert: Jim Idle, and we have been able now after several months of hard work to merge in a complete update to our parsers. This has a massive performance increase between 5-10 times more performant than before. However, we are still not those, we have three more performance phases coming up!

    BL-91 Support numeric literal separators in source code

    We’ve added a small, but useful syntax to our BoxLang parser that comes from multiple other languages. Numeric placeholders allow you to place underscore characters (_) inside of a numeric literal for readability. Take a number like this

    That’s 1 billion. Or was it 1 million? Or maybe it was 100 million… pauses to re-count. With numeric place holders, your code can look like this:

    Ahh, so it was 1 billion! There’s no rules on where you can place the underscores, so long as they are INSIDE the number and not leading or trailing. Heck, this is valid (though pointless):

    You can also place numeric separators in decimals

    and in the exponent of scientific notation

    These underscores are simply thrown away at compile time. They are not represented in the bytecode and will not appear anywhere in your running app. They are purely for readability in your source code.

    BL-457 Add static assignment modifier

    You can now use the static assignment modifier in your code:

    which is sugar for

    and validate at runtime there is actually a static scope, or throw an exception.

    BL-458 Add final modifier to classes

    You can now use the final modifier in your classes

    which is sugar for:

    This means that your classes will not be able to be inherited from.

    BL-459 final modifier for UDFs

    Your UDFs can now also be declared as final

    which will set the function as final into the scope it gets registered into. Any additional function declarations with the same OR ATTEMPTS TO SET A VARIABLE OF THAT NAME will result in an error.

    BL-460 Add final assignment modifier for variables

    You can now add final assignment modifers to variables in your code:

    this, of course, can be used with other modifiers

    The only 2 modifiers that can’t be used together are var and static since they represent different scopes.

    When a variable is declared as final, the scope it is being set into will track a list of keys that are designated as final, and will prevent those keys from being modified in the future.

    This is ONLY a feature of scopes. Structs and other struct-like container will not have a final concept.

    The following example

    cannot be mutated OR re-assigned.


    You can see the Set of final keys for a scope via the meta object

    You can also remove keys from the set to make a variable no longer final.

    BL-469 DynamicInterop now filters non-callable methods when invoking and matching thus accelerating lookups considerably

    This is a major update to our dynamic invocation with Java interop. We know only look at callable methods, where as before we looked at every single method on Java classes. This is a significant boost in performance when doing invocations and well, it also fixes a bug on ambiguity between same named methods with different visibility scopes. Relax and ride the lightning ⚡

    BL-438 Zip Utility & compress(), extract(), isZipFile() bifs

    BoxLang now speaks Zip language. We have added zip and gzip capabilities to the core. This will allow us to leverage compression and extraction for modular activites, jar installations, logging, and much more. We have also created the following BIFS available to you:

    • compress( format, source, destination, [includeBaseFolder=true], overwrite=false ) - Compress a source to a destination using available compression formats.

    • extract( format, source, destination, [overwrite=false], [recurse=true], [filter], [entryPaths] ) - Extract a zip/gzip archive to a destination with nice options.

    • isZipFile( filepath ) : Determines if the passed file can be treated as a zip archive.

    We support the following formats:

    • zip

    • gzip

    More formats will be available for our +/++ subscribers.

    Please note also that the filter arguments can be the following:

    • A valid regular expression string: ".*\.txt"

    • A BoxLang closure or lambda (name) => name.endsWith(".txt")

      • Receives the full path of the entry

    • A Java Predicate: (entry) -> entry.getName().endsWith(".txt")

      • Receives the ZipEntry object

    In our next betas we will have a the Zip component which will allow you to do the following:

    • Compress Files

    • Extract Files

    • List File Entries

    • Delete File Entries

    • Read File Entries

    • Read Binary File Entries

    • Much More.

    BL-447 java.math.BigInteger caster

    We had a BigDecimal caster, now we have a BigInteger caster. Not only that, we can correctly coerce Java interop calls for BigDecimal and BigInteger.

    Improvements

    BL-433 Allow the incorrect foo..bar syntax that Adobe allows for

    BL-446 Cache sets() and getOrSets() does not accept duration in seconds alongside Duration objects.

    BL-455 Enhance ClassMetadataVisitor

    BL-468 Enhance feature audit to track QoQ separate

    BL-456 Validate var outside of a function

    BL-463 Support Adob'e loose comma parsing in their generic tag-in-script syntax

    BL-465 Enhance errors for identifiers starting with numbers

    BL-470 File And Directory BIFs to auto-expand received paths

    BL-431 Support variable starting with number

    Bugs

    BL-461 Compatible encryption with lucee/acf

    BL-462 replace() and replaceNoCase() should accept "one" not "once" for the scope

    BL-464 tag comments not parsing inside output tag in template parsers

    BL-466 parsing fails with extra whitespace in closing output tag

    BL-467 <cfset and <bx:set fail if not followed by a space

    BL-472 Debugger breakpoints not working regression

    BL-473 BoxLang Error is not readable

    BL-454 Tag island Templating outputs in unexpected order

    [General]
    appName=MyApplication
    version=1.2.3
    author=John Doe
    boxlang=rocks
    
    [Database]
    host=localhost
    port=5432
    username=dbuser
    password=dbpass
    dbname=mydatabase
    
    [Logging]
    logLevel=DEBUG
    logFile=/var/log/myapp.log
    maxFileSize=10MB
    
    [Features]
    enableFeatureX=true
    enableFeatureY=false
    maxConnections=100
    // Get the ini file
    var iniFile = getIniFile( "test.ini" );
    iniFile.createSection( "mySettings" );
    // Set a string
    iniFile.setEntry( "section1", "entry1", "value1" );
    // Get a string
    var value = iniFile.getEntry( "section1", "entry1" );
    // Remove a string
    iniFile.removeEntry( "section1", "entry1" );
    // Remove a section
    iniFile.removeSection( "section1" );
    <script>
    let info = "#JSStringFormat( "An example string value with ""quoted"" 'text'" )#"
    </script>
    <bx:xml variable="myVar">
      <root>
        <foo attr="brad" />
        <foo attr="luis" />
        <foo attr="jon" />
      <root>
    </bx:xml>
    setVariable( prepVar(), "hello" )
    
    println( getVariable( getVar() ) )
    boxlang task.cfm
    boxlang script.cfs
    class{
        // serializable
        property name;
        // not serializable
        property boolean isLoggedIn deafult=false serializable=false
    
    }
    n = 1000000000
    n = 1_000_000_000
    n = 1_0_0_0_0_0_0_0_0_0
    n = 3.141_592_653_59
    1e2_345
    static foo = "bar"
    static.foo = "bar"
    final class {}
    class final {}
    final function foo() {
    }
    final function foo() {}
    foo = "brad" // exception because foo is final
    final foo = "bar"
    final static foo = "bar"
    final var foo = "baz"
    final lockDown = [ 1, 2, 3 ].toUnmodifiable()
    variables.$bx.meta.finalKeySet
    final foo = "bar"
    variables.$bx.meta.finalKeySet.clear() // Nothing is final in this scope now
    foo = "baz" // no error
    

    1.0.0-Beta8

    August 2, 2024

    BoxLang Betas are released weekly. This is our eigth beta marker and we are excited to report that we are 100% tag compatible with Adobe/Lucee and 99% BIF compatible. We can estimate that in the next 2 betas we will be 100% compatible with both Adobe/Lucee CFML engines when running BoxLang in compatibility mode.

    Please note that this is our core competency definition. You can see our lists here:

    • BIFS: https://docs.google.com/spreadsheets/d/1SVr9NTYU51n9VyPrKVUjfF3EeEkEnkZOkrNmj1TE120/edit?pli=1&gid=0#gid=0&fvid=1144231850

    • Tags/Components

    New Features

    contractPath() BIF

    This allows you to get a relative path or mapping path from a fully expanded path in your system. This is useful, to understand where a full absolute path comes from:

    Add loop times=n

    We have added a new construct for looping by using the keyword times in your loop statements:

    You can also use times and the index

    Or the item alias can be used as well as the index

    Implement GetBaseTagList() and getBaseTagData()

    These two methods are to bring us closer to finalizing the creation of custom templating language constructs.

    • getBaseTagList( [caller] ) : Gets a comma-delimited list of uppercase ancestor tag names, as a string. The first list element is the current tag. If the current tag is nested, the next element is the parent tag. If the function is called for a top-level tag, it returns an empty string.

    • getBaseTagData( tagName, [level=1] ) : Used within a custom tag. Finds calling (ancestor) tag by name and accesses its data.

    Improve parser error messages for unpopped parser modes

    For code like

    or

    instead of our default “unpopped modes”, detect what specific mode is on the stack (comment_mode, quotesMode, etc), find the start token (comment_start, OPEN_QUOTE, etc) and report the line number that the unclosed construct started, which could be hundreds of lines from the end of the file when parsing finally stopped.

    Transaction events

    The BoxLang JDBC Transactions framework is now complete and incredibly robust. More than the other CFML engines or even Spring-based transaction demarcations. It is fully documented here:

    We have also added several events that you can listen to during the transaction processes:

    • onTransactionBegin

    • onTransactionEnd

    • onTransactionCommit

    Note that all these events (with the exception of onTransactionAcquire and onTransactionRelease) have the potential to be acting upon a no-op transaction, with a null connection parameter since no connection was ever obtained.

    Improvements

    Allow for circular references in structs and arrays

    Java 21 update to URL creation as new URL is deprecated

    add getMimeType method in FileSystemUtil to make it easier to get mime types of remote files ( e.g. PDF creation )

    Bugs

    <bx:loop query="query"> doesn't iterate over each item in the query, stays on the first item

    session scope can be null in onSessionEnd, causing errors

    Tasks

    Create tests for all valid and invalid dot and array access expressions

    1.0.0-Beta5

    July 12, 2024

    BoxLang Betas are released weekly. This is our fifth beta marker. Here are the release notes.

    New Features

    Ability to call on `navigate( String... paths)` on the `Configuration` to create data navigators

    1.0.0-RC.2

    March 4th, 2025

    🚀 BoxLang Release Candidate 2 is Here! 🚀

    We’re entering the final stretch of our pre-releases, and we couldn’t be more excited to introduce RC2! 🚀 This release marks a major leap in performance and compatibility, the result of over six months of intensive development. Beyond enhanced stability and seamless integration, RC2 delivers game-changing performance optimizations that push the boundaries of efficiency. Get ready for our fastest, most refined release yet!

    Feel the Need for Speed 🚀🔥

    RC2 is blazing fast! 🚀 Our latest release delivers unmatched performance in both parsing and runtime execution, outperforming Adobe ColdFusion 2021 and 2023 by 25-37% in many scenarios. These results are backed by rigorous certification testing across TestBox, ColdBox, and over 35 modules, ensuring real-world speed and reliability. You can now check all of our repos and see the performance for yourself.

    1.0.0-Beta9

    August 9, 2024

    BoxLang Betas are released weekly. This is our ninth marker and we are incredibly excited as we are coming close to our stable release. We have some great news in this release!

    New Features

    PDF Module

    onTransactionRollback
  • onTransactionSetSavepoint

  • onTransactionAcquire*

  • onTransactionRelease*

  • https://docs.google.com/spreadsheets/d/1XkCQ8CPXslQWGCr8LHaQcDHZOMiwxST2nzX63_CSzvI/edit?gid=0#gid=0
    BL-394
    BL-395
    BL-396
    BL-397
    BL-408
    https://boxlang.ortusbooks.com/boxlang-framework/transactions
    BL-402
    BL-406
    BL-407
    BL-398
    BL-404
    BL-372

    The entire boxlang.json has now been updated to match the CFConfig project as much as it can. This ticket introduces a new method on the Configuration object that the core team and module developers can use to navigate the configuration structures fluently. The navigate() method produces a BoxLang DataNavigator object, which allows you to navigate in, get keys, cast them, do defaults, and so much more.

    Check out our data navigator docs for further information.

    BL-320 Store the original last configuration seeded into the runtime as `originalConfig`

    The configuration object also stores the original configuration struct from the last loaded boxlang.json. You can navigate it or retrieve it from anywhere within the BoxLang code. This is great for module developers, so they can have any setting they can retrieve later.

    BL-322 New StringBind() bif and member function to bind a string with placeholder replacements using the `${key}`

    We use this methodology everywhere in BoxLang core, so we now expose it as a BIF and member method for strings. The stringBind() allows you to pass in a string template, and bind it with a map of variables for you as long as it adheres to the binding pattern of: ${key:defaultValue}

    You can use it for mail merging, data merging, string templates, and so much more.

    BL-324 attempts now have an isNull() to explicitly determine if the value is null

    We have just started talking about our Attempt class in BoxLang, a Java Optional on Steroids. It allows you to track values and act upon them depending on whether they exists or truthy/falsey. It provides many functional methods to produce fluent DSLs and is easier to work with any attempt at external resources or other things. The core will be moving towards returning attempts whenever it makes sense.

    Please see our docs on Attempts for further information.

    BL-325 Allows Java methods to be referenced and passed around as a variable and invoked later like UDFs

    BL-338 Allow Java functional interfaces and SAMs to be wrapped and used as functions

    We’ve added more goodies to our BoxLang Java interop, this time around method references and high-order functions. BoxLang already allows you to grab a reference to a UDF or closure as a variable, pass it around, and invoke it.

    BL also allows you to grab a reference to a static method from a Box class as well using the :: notation.

    Now, in BoxLang, we’ve elevated Java methods, both instance and static also to be objects you can pass around, invoke, and send into a higher-order function (a function that accepts functions).

    When you reference a method on a Java class without the parenthesis (just like our BL examples above), you will get a special Function instance that wraps up the Java method, allowing it to be treated as a function, passed into any argument which is typed as a function, and invoked headlessly.

    Here, we capture the static value of the Java String class valueOf() method from and place it into a variable, where we invoke it.

    This example captures the toUpperCase method from a String instance. Note the method is still bound to the original String instance and, when invoked, will be invoked against that original instance

    And finally, here we use a Java method to pass directly in place of a UDF or Closure to a higher order function.

    We grab the compare method from Java’s reverse order comparator and pass it directly into the array sort method in BoxLang, reversing our array! Stay tuned, as more features are coming on Java interop.

    BL-326 New Application global defaults in the boxlang.json

    Our configuration is now solid leveraging cfconfig and we have now added several configuration items that will be used as defaults for all applications running under BoxLang. You will find this in the boxlang.json

    BL-330 new interception points when a session get's created and destroyed

    We have introduced two new global interception points that modules can listen to:

    Event
    Data
    Description

    onSessionCreated

    Session

    When a new session is created and registered

    onSessionDestroyed

    Session

    When a session is about to be destroyed

    BL-339 All locations in the cache that returned optionals, now returns BoxLang Attempts

    We have now moved internally from Optionals to Attemps in order to have consistency in our APIs. I am sure there are more things to do, but all cache interfaces and operations now rely on BoxLang Attempts.

    BL-340 getAsAttempt() on the IStruct default methods for convenience

    This is mostly for internal usage, where we can add native Java casting to struct operations to attempts.

    BL-341 BoxCacheProviders now have a localized interceptor pool alongside the runtime pool

    The BoxLang Cache now has a localized interception pool so it can also announce events locally and globally to the runtime. This allows you to have interceptors that can listen only at specific caches instead of all caches. We use this for example, to listen when sessions expire in applications:

    Which brings about the next ticket:

    BL-342 Sessions are now monitored by cache interceptors to detect removals so as to shutdown the sessions before removal

    BL-343 application, session, request timeouts in the boxlang.json are now string timespans

    We have now added the capability to influence the application, request and session timeouts in configuration using the cfconfig standard of a string timespan:

    BL-344 App Timeouts are now working

    The default timeout for applications in BoxLang is 0, which means they live forever. If you want to change it, then you will change it at the boxlang.json level or in the Application.bx/cfc

    Improvements

    BL-209 Combine config settings into a single struct

    BL-318 Allow optional attribute delimiters in ACF tag-in-script syntax

    BL-321 Refactor dump loading of CSS to use caching again

    BL-323 Refactor page pool to be per-mapping

    BL-329 jsessionID is the internal standard for boxlang sessions, move to this instead of cfid

    BL-332 getOrSet() in the cache should return the object not an optional

    Bugs Squashed

    BL-164 BL Compat module should coerce null values to empty string

    BL-252 MSSQL DROP TABLE throws 'The statement must be executed before any results can be obtained'

    BL-306 Adobe Compatibility: Missing support for new java() and new component()

    BL-308 cfinvoke does not support params as attribute-value pairs

    BL-316 If the global runtime `javaLibraryPaths` is already a jar/class location, then use it, else it breaks

    BL-317 allow "var" before CF catch variable in script

    BL-331 ResetSession on the scripting request context was invalidating the new session instead of the old session

    BL-333 Session creation if the default timeout is not a duration, it should treat it as seconds, not milliseconds

    BL-334 Session object was not serializable

    BL-335 Cache was evicting items without reaping

    BL-336 DateTime toString() not accounting for formatter being null

    BL-337 sessionRotate() not copying over old keys due to nullification of keys when invalidating the old session

    BL-319
    expandedPath = expandPath( "/brad" );  // /absolute/path/to/brad
    contractPath( expandedPath ); // /brad
    loop times=5 {
        result &= "*";
    }
    loop times=5 index="i" {
        result &= i;
    }
    loop times=5 item="i" {
        result &= i;
    }
    <--- I never end
    foo = "trumcated...
    Configuration
        .navigate( "modules" )
        .ifPresent( "security", value -> this.name = Key.of( value ) );
    var renderInHtml = Configuration
        .navigate( "originalConfig", "modules", "pdf" )
        .getAsBoolean( "htmlREnder", false )
    function renderMail(){
        myTemplate = """
        Hello ${name},
        
        I hope you have an awesome ${action} using BoxLang v${version:snapshot}
        """
        
        return stringBind( myTemplate, { 
            name : "Luis Majano",
            action : "Day"
        } );
    }
    
    function renderMail(){
        return """
        Hello ${name},
        
        I hope you have an awesome ${action} using BoxLang v${version:snapshot}
        """.bind( { 
            name : "Luis Majano",
            action : "Day"
        } );
    }
    var userFound = attempt( userService.findBy( rc.id ) ).isNull()
    myInstance = new myClass();
    myInstanceMethod = myInstance.myMethod;
    myInstanceMethod();
    myStaticUDF = src.test.java.TestCases.phase3.StaticTest::sayHello;
    myStaticUDF();
    import java:java.lang.String;
    javaStaticMethod = java.lang.String::valueOf;
    result = javaStaticMethod( "test" ) // New string of "test"
    javaInstanceMethod = "my string".toUpperCase
    result = javaInstanceMethod() // "MY STRING"
    import java.util.Collections;
    // Use the compare method from the Java reverse order comparator to sort a BL array
    [ 1, 7, 3, 99, 0 ].sort( Collections.reverseOrder().compare  ) // [ 99, 7, 3, 1, 0 ]
    // The default timezone for the runtime; defaults to the JVM timezone if empty
    // Please use the IANA timezone database values
    "timezone": "",
    // The default locale for the runtime; defaults to the JVM locale if empty
    // Please use the IETF BCP 47 language tag values
    "locale": "",
    // If true, you can call implicit accessors/mutators on object properties. By default it is enabled
    // You can turn it on here for all applications or in the Application.cfc
    "invokeImplicitAccessor": true,
    // Use Timespan syntax: "days, hours, minutes, seconds"
    "applicationTimeout": "0,0,0,0",
    // The request timeout for a request in seconds; 0 means no timeout
    "requestTimeout": "0,0,0,0",
    // The session timeout: 30 minutes
    "sessionTimeout": "0,0,30,0",
    // Where sessions will be stored by default.  This has to be a name of a registered cache
    // or the keyword "memory" to indicate our auto-created cache.
    // This will apply to ALL applications unless overridden in the Application.cfc
    "sessionStorage": "memory",
    // Set client cookies on applications
    "setClientCookies" : true,
    // Set domain cookies on applications
    "setDomainCookies" : true,
    // A collection of BoxLang mappings, the key is the prefix and the value is the directory
    "mappings": {
    	"/": "${user-dir}"
    },
    // A collection of BoxLang custom tag directories, they must be absolute paths
    "customTagsDirectory": [
    	"${boxlang-home}/customTags"
    ],
    // A collection of directories we will class load all Java *.jar files from
    "javaLibraryPaths": [
    	"${boxlang-home}/lib"
    ],
    // You can assign a global default datasource to be used in the language
    "defaultDasource": "",
    // The registered global datasources in the language
    // The key is the name of the datasource and the value is a struct of the datasource settings
    "datasources": {
    	// "testDB": {
    	// 	  "driver": "derby",
    	//    "connectionString": "jdbc:derby:memory:testDB;create=true"
    	// }
    	// "testdatasource": {
    	// 	  "driver": "derby",
    	// 	  "host": "localhost",
    	// 	  "port": 3306,
    	// 	  "database": "test"
    	// }
    },
    return getBoxCache()
        .get( "maybeExists" )
        .orElse( "not found" );
    // Register the session cleanup interceptor
    this.sessionsCache.getInterceptorPool()
        .register( data -> {
    	    ICacheProvider targetCache = ( ICacheProvider ) data.get( "cache" );
    	    String		key			= ( String ) data.get( "key" );
    
    	    logger.debug( "Session cache interceptor [{}] cleared key [{}]", targetCache.getName(), key );
    
    	    targetCache
    	        .get( key )
    	        .ifPresent( session -> ( ( Session ) session ).shutdown( this.startingListener ) );
    
    	    return false;
        }, BoxEvent.BEFORE_CACHE_ELEMENT_REMOVED.key() );
    // Use Timespan syntax: "days, hours, minutes, seconds"
    "applicationTimeout": "0,0,0,0",
    // The request timeout for a request in seconds; 0 means no timeout
    "requestTimeout": "0,0,0,0",
    // The session timeout: 30 minutes
    "sessionTimeout": "0,0,30,0",

    Adobe ColdFusion / Lucee Drop-In Replacement

    This means you can seamlessly migrate your Adobe ColdFusion or Lucee applications to BoxLang with no code changes—and they’ll run faster, smoother, and across multiple runtimes! 🚀

    But that’s not all—our subscription-based licensing can save you over 70% compared to Adobe ColdFusion, with no restrictions on cores or limitations on SaaS and multi-tenant applications. No restrictions. Just pure freedom to scale. 🔥

    Ray Camden BoxLang Evangelist

    We’re excited to welcome Raymond Camden, a renowned leader in the CFML community, as a BoxLang Advocate! 🎉

    Raymond, currently collaborating with us as a contractor, brings deep expertise in web development and a passion for making complex technologies more accessible. His insights and experience make him the perfect advocate to explore and champion BoxLang—our modern, CFML-compatible programming language. 🚀

    Read More

    Premium Modules Have Landed

    We have now our first premium module for BoxLang +/++ subscribers: BX-REDIS. Our bx-redismodule is now available for you to use if you have a subscription. You can also try it out free of charge by installing it today:

    Giving you great capabilities for caching, distributed sessions, pub-subscribe and much more. You can find out about this initial release here (https://forgebox.io/view/bx-redis)

    Licenses Available!

    Remember that our support license subscriptions (https://www.boxlang.io/plans) for BoxLang +/++ are available now. Offering enterprise-grade support, priority fixes, premium modules, and exclusive benefits. As an introductory offer, all licenses are available at 25% off for March.

    Production Tips

    We encourage you to pre-compile your applications using our BoxLang compiler for incredibly safe and high-performance deployments since no parsing is involved. Combined with our new trusted cache settings, your applications will fly and be highly performant.


    Release Notes

    Improvements

    BL-1021 Explore speed improvements to parser

    BL-1084 Support CF syntax of space inside elvis operator

    BL-1089 allow getSystemSetting() to default to a non-simple value

    BL-1090 bx-compat - Client Scope Listener should not start up or look for cache if client management is disabled

    BL-1093 Make miniserver bind to 0.0.0.0 by default

    BL-1143 Change order of app shutdown

    BL-1147 boxAnnounce() and boxAnnounceAsync() get a poolname so you can announce globally or to the request pools

    BL-1148 missing bif: BoxRegisterInterceptionPoints() to register interception points for global or request pools

    BL-1149 In BL files, only default output=false in tag-based UDFs

    BL-1153 Setup the hikari defaults for connection pooling to modern standards

    BL-1155 Update query object to return array of structs into a consolidated method: toArrayOfStructs()

    BL-1158 Attempts needed remail of left over isSimplevalue evaluations

    BL-1159 Rename bx:module to be bx:component

    Bugs

    BL-1018 esapiEncode does not allow an zero length input string

    BL-1024 BX-ORM: Datasource with name [defaultDatasource] not found in the application or globally

    BL-1026 `try`/`finally` doesn't always run `finally`

    BL-1036 ASM regression - break exiting out of more than just the loop

    BL-1056 LinkedHashMap right-hand assignments are always null.

    BL-1063 ReEscape result doesn't match ACF

    BL-1064 Classes getting cleared in debug mode

    BL-1077 Simplify CLI to install modules

    BL-1078 cgi items not being found until you access them

    BL-1079 encrypt not working with AES and UU

    BL-1080 Encrypt Fails when salt is below 16 bytes in length

    BL-1082 bx-mail not reading mail configurations

    BL-1085 HTTP - Ensure all exceptions are caught and handled

    BL-1086 Mail Module not Loading root-level boxlang.json Mail Server Settings

    BL-1087 StructUtil.deepMerge wraps arrays in nested array if left hand side contains the same array

    BL-1088 Can't set cookies using a struct

    BL-1092 Mail: Classloader issues when sending MultiPart email in Servlet Context

    BL-1094 `.duplicate()` Member Method Not Available on Struct,DateTime objects, Queries and Arrays

    BL-1095 DirectoryCopy Does not Allow Closure for Filter Arg

    BL-1096 QueryNew Does not accept array of Columns as only first arg

    BL-1097 Compat: CachePut does not allow numeric decimal number of days for timeSpan or idleTime

    BL-1099 String Hash Result Different Between Text and Byte Array

    BL-1100 Compat: HTTP result.statusCode Does not Include the status text.

    BL-1101 HTTP Request for Binary Object casts fileContent to String

    BL-1102 Integer caster not always consistent

    BL-1103 HTTP Component getAsBinary attribute does not support `true` and `false` boolean arguments

    BL-1104 HTTP Component throws an error when `Host` is explicitly passed as a header

    BL-1105 HTTP Component Throws Error when sending Binary Content

    BL-1106 HTTP getAsBinary should be treated as an explicit request for binary content unless `never` is passed.

    BL-1109 HTTP: Query Params Are Being Double Encoded Even When Encode=false

    BL-1110 Within a cfmodule, the variables scope is not available within a .each() loop if the .each loop is called in a function within the module.

    BL-1111 When a form is submitted but none of the inputs have names and the form scope is dumped, an error is thrown

    BL-1112 Type coercion of an numeric argument passed to java constructor is not being done

    BL-1113 Function NOT not found

    BL-1114 bx-orm - 'Datasource with name [defaultDatasource] not found ...'

    BL-1115 bx-orm - Unable to call generated methods from within class

    BL-1116 bx-orm - Generated method hasX() is missing support for value comparison

    BL-1117 bx-orm - AddX() method fails on many-to-many relationship properties with "bag is null" error

    BL-1118 HMAC Method not supporting binary keys

    BL-1120 HTTP `file` attribute not implemented

    BL-1121 Math Operations Leave trailing zeros after operation when result is whole number

    BL-1122 HTTP ACF and Lucee Treat all Unknown or malformed `Content-Type` Headers as a string response

    BL-1124 Compat: Default throw error not a type of `Application`

    BL-1125 Error compiling - 'in' was unexpected expecting one of ...

    BL-1126 this.customtagpaths not respected - Could not find custom tag

    BL-1128 Common Text Cert/Key extensions are being read as Binary data

    BL-1129 for loop using var and in throws parsing error

    BL-1130 Custom Error Thrown Is Being Wrapped in "Error invoking Supplier" exception

    BL-1132 FileRead should only ever return strings

    BL-1133 DateTime Comparison equals/isEqual discrepancies

    BL-1134 DateCompare Issues when Time units are specified

    BL-1135 DateAdd No Longer Allowing Decimals

    BL-1137 Allow customTagPaths to be relative

    BL-1138 EqualsEquals operator should use `equalTo` method of DateTime in compat mode

    BL-1139 Cannot pass BoxLang Functions into ScheduledTask

    BL-1140 Nested config values for modules do not get replaced by environment variables

    BL-1142 thread safety issue in feature audit

    BL-1144 Custom setter that assigns to this scope causes stack overflow with implicit accessor invocation

    BL-1146 return type of function not always parsing

    BL-1150 Invalid stack height when using a ternary in a context that doesn't expect a return value

    BL-1151 semicolon not allowed after pre annotation

    BL-1152 `variablename` is not supported as a type

    BL-1156 Compat: Date Comparisons in Compat should only be precise to the second

    BL-1157 len() BIF needs to treat byte arrays as an array, not a string

    BL-1160 return not expr parsing error

    Tasks

    BL-814 CBSecurity Certification

    BL-1076 isWDDX BIF missing from wddx module

    Planswww.boxlang.io
    www.boxlang.io/plans
    PDFs have landed for BoxLang. The full implementation for creating PDF documents is now complete and available via our bx-pdf module. This module contributes the following Components to the language:
    • document - the wrapping component for creating PDF documents

      • The following attributes are available to the document component

        • format - The format of the document to generate. This attribute is unused and will be removed in a future release as only PDF generation is supported. Any other format requested will throw an error.

        • encryption - The encryption level to use for the document. Default is none. Possible values are 128-bit, 40-bit, none

        • localUrl - If true, the document will be generated with local URLs. Default is false

        • variable - The name of the variable to store the generated PDF binary

        • backgroundVisible - If true, the background will be visible. Default is true

        • bookmark - If true, bookmarks will be generated. Default is true

        • htmlBookmark - If true, it is possible to convert outlines to a list of named anchors (<a name="anchor_id">label</a>) or a headings structure ( <h1>... <h6> ). Transforming of HTML hyperlinks to PDF hyperlinks (if not explicitly disabled Hyperlink jumps within the same document are supported as well

        • orientation - The orientation of the document. Default is portrait. Possible values are portrait, landscape

        • scale - The percentage to scale the document. Must be less than 100

        • marginBottom - The bottom margin of the document

        • marginLeft - The left margin of the document

        • marginRight - The right margin of the document

        • marginTop - The top margin of the document

        • pageWidth - The width of the page in inches

        • pageHeight - The height of the page in inches

        • fontEmbed - If true, fonts will be embedded in the document. Default is true

        • fontDirectory - The directory where fonts are located

        • openpassword - The password to open protected documents

        • ownerPassword - The password to access restricted permissions

        • pageType - The type of page to generate. Default is A4.

        • pdfa - If true, the document will be generated as a PDF/A document. Default is false

        • filename - The filename to write the PDF to. If not provided and a variable argument is not provided, the PDF will be written to the browser ( Web-context only )

        • overwrite - If true, the file will be overwritten if it exists. Default is false

        • saveAsName - The name to save the PDF as in the browser

        • src - A full URL or path relative to the web root of the source

        • srcfile - The absolute path to a source file

        • mimeType - The mime type of the source. Default is text/html. Possible values are text/html, text/plain, application/xml, image/jpeg, image/png, image/bmp, image/gif

        • unit - The unit of measurement to use. Default is inches. Possible values are in, cm

      • The following attributes are not currently implemented and will throw an error if used

        • permissions - Granular permissability is not yet supported

        • permissionspassword - Granular permissability is not yet supported

    • documentitem - specifies header, footer, and pagebreaks within a document body or documentsection

      • The following attributes are available to the documentitem component

        • type A string which dictates the type of item. Accepted values are

    • documentsection - Divides a PDF document into sections. Used in conjunction with a documentitem component, each section can have unique headers, footers, and page numbers. A page break will always precede a section

      • The following attributes are available to the documentsection component

        • marginBottom

    Examples

    Simple example using tag-based syntax to generate a physical file:

    Example using script syntax to create a variable containing the binary contents of the PDF, which is then written to a file

    BL-110 objectLoad() and objectSave() implemented and renamed to objectSerialize() and objectDeserialize()

    This is a really step forward for BoxLang in providing the ability to serialize and deserialize any BoxLang type and any BoxLang class to binary recursively n-levels deep. We have introduced two BIFS to accomplish this:

    • objectSerialize( object, [filepath] ) : binary

    • objectDeserialize( input ) : object

    You can pass ANY object to the serialize function and it will recursively try to serialize the object to binary data. You can then store that in a database, cluster, cache, or a file using the filepath argument. To deserialize you can use the objectDeserialize() function and you can pass in the direct binary or a file path location for the binary.

    The only requirement is that the object be a BoxLang type or any Java type that implements serializable.

    Also note that for CFML compatibility, the compat module will expose them as objectLoad() and objectSave().

    BL-420 Exit REPL with quit or exit

    You can now exit the BoxLang REPL by typing quit or exit.

    BL-422 Ability to serialize BoxLang classes to binary and deserialize them back using it's state

    This was related to BL-110 but specifically to BoxLang classes. This allows us now to be able to take the state of any BoxLang class and be able to serialize it to binary. You can then deserialize the binary and inflate it back to a BoxLang object graph again.

    BL-423 New experimental features block on the `boxlang.json`

    The boxlang.json get's a new top level configuration key: experimental which will be a feature flags approach to turn on/off experimental features in BoxLang.

    BL-424 BoxRunner action commands now for: compile, cftranspile, featureAudit

    We have consolidated our CLI tooling to all funnel through the boxlang binary script or boxlang.bat for windows. You can now execute our CLI tools via action commands which is based on the following keys:

    • compile - Executes the BoxLang compiler tool

    • cftranspile - Executes the CF to BoxLang transpile tool

    • featureAudit - Executes the feature audit tool

    Improvements

    BL-414 Renaming of Box Cache functions to standardized cache{function}()

    The BoxLang Cache BIFs have been renamed to be standardized to the following:

    • cache( [provider:default] )

    • cacheFilter()

    • cacheNames()

    • cacheProviders()

    • cacheService()

    BL-415 Increase precision of math operations by using BigDecimal

    This introduces BigDecimal usage all over BoxLang for two main use cases:

    • Being able to store and process very large numbers that wouldn't fit inside a Long or a Double like 111111111111111111111111111 + 222222222222222222222222222

    • Being able to retain precision for decimals-- even small ones. For ex: (0.1 + 0.2).toString() outputs 0.30000000000000004 in Lucee 5 and ACF 2023. But in Lucee 6 and BoxLang, it correctly returns .3 without any special work

    Not ALL numbers are a BigDecimal-- just the ones that need to be:

    • integer literals in your source code less than 11 chars will be a java Integer

    • integer literals in your source code less than 20 chars will be a java Long

    • All other integer literals in your source will be a java BigDecimal

    • All decimal literals in your source will be a java BigDecimal

    Furthermore, we have added a new NumberCaster which we should be using as our primary caster that returns an instance implementing the Number interface in Java

    • any recognizable classes like int, long, double, big decimal, etc are just returned directly

    • Any strings which contain integers (no decimal or sci notation) follow the same rules above (integer for small ones, long for bigger ones, big decimal for really big ones)

    • Any strings with a decimal or sci notation will be made a BigDecimal

    Basically, we return the "Smallest" data type we can without losing any precision. (An Integer is about 24 Bytes and a BigDecimal is about 64 Bytes so it seemed worth optimizing a bit)

    BL-421 Finalize FileUpload, FileUploadAll BIFs and File Component upload actions in Web Support

    The web runtimes now have file uploading capabiltiies finalized.

    Bugs

    BL-405 BigIntegers cause error: integer number too large

    BL-419 Not all unquoted tag attribute values are parsing

    BL-105

    1.3.0

    June 23, 2025

    We're excited to announce BoxLang v1.3.0, a significant update that brings new features, performance improvements, and important bug fixes to enhance your development experience.

    🎉 New Features

    Compression & Serialization Enhancements

    Enhanced Zip Component (BL-1508)

    Added compressionLevel parameter to zip component and utilities for better control over compression settings. The default compressionLevel is 6 which is a balanced approach.

    Example:

    Pretty JSON Serialization (BL-1542)

    Added pretty argument to jsonSerialize() function to enable formatted JSON output for improved readability and storage.

    Example:

    Array, List, Query & Struct Operations

    New xNone() Functions (BL-1533)

    Introduced xNone() functions for BIF operations across arrays, lists, queries, and structs to check if no elements match specified criteria.

    Array Example:

    List Example:

    Query Example:

    Struct Example:

    Build & Security Improvements

    Binary Checksums (BL-1512)

    Added checksums to all binary creations in the build process for enhanced security and integrity verification.

    Usage in CI/CD:

    🚀 Improvements

    Documentation & Developer Experience

    • Enhanced Documentation (BL-1471): Added comprehensive examples to documentation for Built-in Functions (BIFs) and Components

    • Command Line Help (BL-1521, BL-1522): Added --help and -h flags to Mini Server, Feature Audit, CFTranspiler, Scheduler, BoxRunner, and other command-line tools

    Performance & Architecture

    • HTTP Response Compression (BL-1511): Added support for compressed HTTP responses to improve performance

    • Query Concurrency (BL-1534): Significant improvements to query concurrency handling, resolving inconsistencies when adding data to queries in parallel threads

    • Lazy Cache Expiration (BL-1528): Implemented lazy expiration for caching to optimize memory usage and performance

    • Scope Security

    Error Handling & Type Safety

    • Array Type Matching (BL-1516): Updated arrayFind() to handle mismatched types gracefully without throwing exceptions

    • Compile-time Annotations (BL-1537): Refactored @NonNull and @Nullable annotations to use compile-time checkers instead of runtime dependencies

    Dependency Updates

    • Semver4j Update (BL-1526): Bumped org.semver4j:semver4j from 5.7.0 to 5.7.1

    • Jackson Update (BL-1536): Bumped com.fasterxml.jackson.jr:jackson-jr-stree from 2.19.0 to 2.19.1

    • Runtime Dependencies (BL-1519): Optimized to ensure only runtime dependencies are stored in the lib folder

    CFML Compatibility

    • CFQuery Parameter Mapping (BL-1544): Created transpiler rule for cfquery params, mapping cfsqltype to sqltype for better CFML compatibility

    🐛 Bug Fixes

    Image Processing

    • Image Scaling (BL-1216): Fixed issue where scaleToFit was creating black images

    • Member Function Resize (BL-1217): Resolved image resize functionality when used as member function

    Database & Transactions

    • JDBC Transaction Handling (BL-1472): Fixed transaction defaults to use app-default datasource instead of ignoring named datasources in queries

    • DATETIME Parameter Aliasing (BL-1527): Resolved issue where DATETIME was not being properly aliased by query parameters in prepared statements

    Mathematical Operations

    • Timestamp Math Operations (BL-1501): Updated math operations encountering timestamps to cast as fractional days for CFML compatibility

    • fix() Function Behavior (BL-1513): Aligned fix() function behavior with Lucee's implementation

    Parallel Processing

    • Tiered Execution (BL-1503): Updated parallel computations (xSome, xEvery, xMap, xFilter, xEach) to use improved tiered execution approach

    • Loop Group Handling (BL-1504): Fixed issue where looping groups would break instead of continuing properly

    File Handling & HTTP

    • File Upload Errors (BL-1507): Resolved HTTP errors occurring during file uploads

    • Multi-part Form Fields (BL-1523): Fixed issue where all multi-part form fields were being unnecessarily written to disk

    Exception Handling

    • CFCatch Support (BL-1524): Improved CFCatch support when catch variable is defined in bx-compat-cfml

    Caching System

    • Cache Concurrency (BL-1529): Resolved several concurrency issues affecting cache entries, creation timeouts, and last access timeouts

    • Cache Entry Collisions (BL-1530): Fixed cache entry equals evaluation that was incorrectly evaluating hash codes and causing collisions

    Class & Component System

    • Remote Method Templates (BL-1531): Improved base template setting for remote methods in super classes

    • Class Metadata (BL-1541): Fixed type property in class metadata to properly reference "class" instead of "component"

    • XML Object Duplication (BL-1547): Resolved issue with duplicate function being broken when using XML objects

    Path Handling

    • Servlet Path Resolution (BL-1532): Enhanced handling of ../ patterns in servlet paths for better security and reliability


    📋 Summary

    BoxLang v1.3.0 delivers significant improvements across performance, reliability, and developer experience. With enhanced concurrency handling, improved caching mechanisms, and comprehensive bug fixes, this release strengthens BoxLang's foundation while maintaining excellent CFML compatibility.

    Key Highlights:

    • New compression and serialization capabilities

    • Major query concurrency improvements

    • Enhanced caching with lazy expiration

    • Comprehensive documentation updates

    We recommend all users upgrade to v1.3.0 to benefit from these improvements and fixes.

    For technical support or questions about this release, please visit our documentation or contact our support team.


    Raw Release Notes

    New Feature

    Add `compressionLevel` to the zip component and utilities

    Add checksums to all binary creations in the build process

    xNone() for bif operations: array, list, query, struct

    Added `pretty` argument to jsonSerialize() to allow for pretty serialization

    Improvement

    Add Examples to docs for BIFs and Components

    Don't allow scopes to be "overridden" with scope hunting

    Add Support for Compressed HTTP responses

    arrayFind shouldn't throw on mismatched types

    Small update to make sure only runtime dependencies are stored in the `lib` folder using our maven pom in the Boxlang home.

    Add --help -h to Mini Server

    Add --help -h to Feature Audit, CFTranspiler, Scheduler, BoxRunner and more

    Bumps org.semver4j:semver4j from 5.7.0 to 5.7.1.

    Add lazy expiration for caching

    Query Concurrency Improvements : There are some inconsistencies and issues when dealing with adding data to queries in parallel threads

    Bumps com.fasterxml.jackson.jr:jackson-jr-stree from 2.19.0 to 2.19.1.

    Refactor @NonNull and @Nullable to use compile time checkers instead of runtime dependencies

    Create a transpiler rule for cfquery params: `cfsqltype` to `sqltype`

    Bugs

    Image scaleToFit creating black images

    Image resize not working as member func.

    JDBC - Transaction defaults to app-default datasource, and ignores the datasource named in the first query

    Compat: Math Operations Which Encounter Timestamps Should Cast as Fractional Days

    Update parallel computations to use a tiered execution approach; xSome, xEvery, xMap, xFilter, xEach

    looping groups breaks when it should continue

    HTTP Errors When Uploading File

    fix() behaviour is not equal to Lucee's behaviour

    All multi-part form fields are being written to disk

    CFCatch support when catch variable defined in bx-compat-cfml

    DATETIME is not being aliased by query parameters in prepared statements

    Several concurrency issues on cache entries created and last access timeouts

    cache entry equals evaluating the hash codes incorrectly and causing collisions

    Set base template for remote methods in super class

    Better handle ../ in servlet paths

    The `type` property in class metadata still references "component" instead of being "class"

    duplicate function broken when using xml objects

    1.0.0-Beta2

    June 21, 2024

    BoxLang Betas are released weekly. This is our second beta marker. Here are the release notes.

    Bug

    BL-140 Writedump expanded collapsed support

    BL-141 Writedump top support

    BL-193 listdeleteAt returns a list with multiple delimiters as a list with whole delimiters

    StructNew with localeSensitive flag throws error

    structKeyTranslate returns void

    StructGet does not create struct when missing

    StructFindValue returning null owner

    no named applications not auto creating name

    application listener requests interception points not registered

    ambiguous if statements when not using curly braces

    this.javasettings not expanding / to correct pathing

    this.javasettings ignores paths to actual jars and classes

    cfdirectory fails on centos, converting datetime

    dateAdd() modifies its argument!

    `toString` not formatting doubles correctly

    Attempt to cast instead of expecting strings inside `isValid`

    Regression on JSON serialization of box classes with JSON exclude annotations

    New Features

    Encryption module

    We have created the bx-password-encrypt module so you can use it for password encryption. Find out much more here:

    This will collaborate several new BIFs and components:

    • ArgonHash: Returns a secure input hash of the given string using the Argon2 hashing algorithm. ( Alias: GenerateArgon2Hash )

    • ArgonVerify: Performs a Argon2 verification on the given string against the hashed value. ( Alias: Argon2CheckHash )

    • BCryptHash

    New event: ON_REQUEST_FLUSH_BUFFER

    You can now listen to when the engine flushes the output buffer and intercepts it. This will allow you to collaborate content to the buffer before it's sent to the output destination. The data received is:

    • context - The execution context

    • output - The string output to send to the buffer. This can be text or HTML

    Ability to coerce BoxLang functions, lambdas, and UDFs, to well-known functional interfaces for Java interop

    This is one of our biggest tickets for this release to continue to close the Java interop cycle in BoxLang. This will allow BoxLang lambdas/closures/udfs to be coerced to Java Functional Interfaces at runtime. This means that ANY Java library that offers functional interfaces (lambdas) can be used natively in BoxLang. This means that using streams, completable futures, and Java lambdas are now native to BoxLang.

    This can also be used to tap into high concurrency constructs in Java. You can combine the usage of BoxLang pure functions (lambdas) or context-aware closures.

    Add parallel streams from BoxLang arrays

    All BoxLang arrays have native stream support, and you get native parallel support as well.

    Truthy / Falsey completion for boolean caster

    Our truthy/false evaluations for arrays, structs, queries, Java lists, and collections are complete.

    New Fluent Attempt bif and class

    This is inspired by Java Optionals for BoxLang. We have introduced a new class called Attempt(), which allows you to create fluent and functional code to work with values or delay attempts at code execution. Then, you can interact with the result of your attempt using our functional methods.

    Another important aspect of attempts is that they evaluate that the seeded value is not null but also truthy. This means you can use it to evaluate that the value is truthy or false, not only null. You can also pass in a closure/lambda to be the value and once you request to evaluate the result, it will do it asynchronously and delayed.

    Here are the current functions available to you in this beta. There are more coming to make it more fluent.

    • get():any - Get the value or throw an exception if null or falsey

    • empty():Attempt - Produce a new empty attempt

    • of( value ):Attempt - Produce a new attempt with the passed value

    Add the ability to add member methods to BoxLang classes

    This was something we always wanted to do. This allows module and BoxLang developers to contribute member methods to ANY BoxLang class. So now, you can serialize any Class to JSON natively using our BoxLang Class to JSON native serialization. Let's build a Person class:

    As you can see, we have introduced a few annotations for JSON serialization based on our experience with the ColdBox mementifier project. You can tag properties to be excluded from serialization using the jsonExclude annotation. You can exclude a list of properties from the class annotation as well. Now, let's get some JSON data out using the toJSON() member function, which delegates it to the jsonSerialize() bif.

    This will allow framework developers to collaborate with first-class methods in any BoxLang class.

    new static helper on Array class: `fromString( list, delimiter )` to create quick BoxLang arrays from strings

    This is an internal convenience method for creating BoxLang arrays from strings.

    new BIFS for registered interceptors into the request pool and the global pool: BoxRegisterREquestInterceptor, BoxRegisterInterceptor

    BoxLang is an event-driven language. It announces tons of events during the software life cycle. You can now listen to any global event via the new BoxRegisterInterceptor() bif. This will allow you to register classes, lambdas, or closures.

    However, BoxLang also offers interceptors at the request level via the internal application listener. This means that you can listen to a specific request life-cycle by using the boxRegisterRequestInterceptor() bif.

    writedump abort support

    More work towards compatibility is completed.

    writeoutput on complex BoxLang types should call the `toString()` on it

    This has been a heached in current CFML engines. We now detect what you send in to the writeOutput() or echo() commands and we will convert them to string if they are complex objects or classes.

    Native Encrypt, Decrypt and GenerateSecretKey()

    We now support all encryption and decryption algorithms natively in BoxLang without ANY third-party library. Secure by default and with 3 BIFS created for this. Supported algorithms:

    • AES

    • ARCFOUR

    • Blowfish

    • ChaCha20

    1.2.0

    May 29, 2025

    BoxLang 1.2: Performance-Driven Innovation

    We're excited to announce the release of BoxLang 1.2, a significant milestone that demonstrates our commitment to delivering both cutting-edge features and exceptional performance. This release represents how much innovation the entire BoxLang team can accomplish in just 2 weeks of focused development, bringing you powerful new capabilities while dramatically improving the runtime efficiency that makes BoxLang a compelling choice for modern applications.

    # OS
    install-bx-module bx-redis
    
    # CommandBox
    box install bx-redis
    <bx:set testImage = "https://ortus-public.s3.amazonaws.com/logos/ortus-medium.jpg"/>
    <bx:document format="pdf" filename="/path/to/mydocument.pdf">
        <!--- Header for all sections --->
        <bx:documentitem type="header">
            <h1>This is my Header</h1>
        </bx:documentitem>
        <!--- Footer for all sections --->
        <bx:documentitem type="footer">
            <h1>This is My Footer</h1>
            <bx:output><p>Page #bxdocument.currentpagenumber# of #bxdocument.totalpages#</p></bx:output>
        </bx:documentitem>
        <!--- Document section, which will be bookmarked as "Section 1" --->
        <bx:documentsection name="Section 1">
            <h1>Section 1</h1>
        </bx:documentsection>
        <!--- Document section, which will be bookmarked as "Section 2" --->
        <bx:documentsection name="Section 2">
            <h1>Section 2</h1>
        </bx:documentsection>
        <!--- Document section, which contains an image --->
        <bx:documentsection src="#testImage#">
    </bx:document>
    document format="pdf" variable="myPDF"{
        documentsection name="Section 1"{
            writeOutput("<h1>Section 1</h1>");
            include "/path/to/section1.bxm";
        }
        documentsection name="Section 2"{
            writeOutput("<h1>Section 2</h1>");
            include "/path/to/section2.bxm";
        }
    }
    
    fileWrite( "/path/to/mydocument.pdf", myPDF );
    > quit
    
    > exit
    "experimental" : {
        "flag1" : true|false
    }
    boxlang compile <options>
    boxlang cftranspile <options>
    boxlang featureAudit <options>
    userPassword - Granular permissability is not yet supported
  • authPassword - Granular permissability is not yet supported

  • authUser - Granular permissability is not yet supported

  • userAgent - HTTP user agent identifier

  • proxyHost - IP address or server name for proxy host

  • proxyPassword - password for the proxy host

  • proxyPort - port of the proxy host

  • proxyUser - user name for the proxy host

  • tagged - yes|no ACF OpenOffice integration not supported

  • formfields - yes|no Form field attributes are not implemented in standard module

  • formsType - FDF|PDF|HTML|XML Form field attributes are not implemented in standard module

  • pagebreak
    |
    header
    |
    footer
  • evalAtPrint This attribute is deprecated as all content is evaluated when the body of the tag is processed

  • - The bottom margin of the section in the unit specified in the
    document
    component.
  • marginLeft - The left margin of the section in the unit specified in the document component.

  • marginRight - The right margin of the section in the unit specified in the document component.

  • marginTop - The top margin of the section in the unit specified in the document component.

  • mimeType - The mime type of the content. If the content is a file, the mime type is determined by the file extension. If the content is a URL, the mime type is determined by the HTTP response.

  • name - The name of the section. This is used as a bookmark for the section.

  • srcfile - The absolute path of the file to include in the section.

  • src - The URL or path relative to the web root of the content to include in the section.

  • The following attributes are not currently implemented and will throw an error if used

    • userAgent - The HTTP user agent identifier to use when fetching the content from a URL.

    • authPassword - The authentication password to use when fetching the content from a URL.

    • authUser - The authentication user name to use when fetching the content from a URL.

  • (BL-1494): Prevented scopes from being overridden through scope hunting for better security
    Critical bug fixes for image processing, database operations, and parallel processing
    BL-1508
    BL-1512
    BL-1533
    BL-1542
    BL-1471
    BL-1494
    BL-1511
    BL-1516
    BL-1519
    BL-1521
    BL-1522
    BL-1526
    BL-1528
    BL-1534
    BL-1536
    BL-1537
    BL-1544
    BL-1216
    BL-1217
    BL-1472
    BL-1501
    BL-1503
    BL-1504
    BL-1507
    BL-1513
    BL-1523
    BL-1524
    BL-1527
    BL-1529
    BL-1530
    BL-1531
    BL-1532
    BL-1541
    BL-1547
    // Zip Component
    bx:zip compressionLevel="9"
    
    // Compress BIF
    compress( compressionLevel: 9 )
    data = {
        name: "John Doe",
        age: 30,
        address: {
            street: "123 Main St",
            city: "Anytown",
            country: "USA"
        },
        hobbies: ["reading", "cycling", "photography"]
    };
    
    // Standard compact JSON (default behavior)
    compactJson = jsonSerialize( data );
    // Output: {"name":"John Doe","age":30,"address":{"street":"123 Main St","city":"Anytown","country":"USA"},"hobbies":["reading","cycling","photography"]}
    
    // Pretty formatted JSON (new feature)
    prettyJson = jsonSerialize( data, pretty=true );
    /* Output:
    {
      "name" : "John Doe",
      "age" : 30,
      "address" : {
        "street" : "123 Main St",
        "city" : "Anytown",
        "country" : "USA"
      },
      "hobbies" : [ "reading", "cycling", "photography" ]
    }
    */
    
    // Useful for debugging and configuration files
    writeFile( "config.json", jsonSerialize( appConfig, pretty=true ) );
    numbers = [ 1, 3, 5, 7, 9 ]
    
    // Using BIF with lambda notation
    hasNoEvens = arrayNone( numbers, num -> num % 2 == 0 )
    // Returns: true (no even numbers found)
    
    hasNoneGreaterThan10 = arrayNone( numbers, num -> num > 10 )
    // Returns: true (no numbers greater than 10)
    
    // Using member method with lambda notation
    hasNoEvens = numbers.none( num -> num % 2 == 0 )
    // Returns: true (no even numbers found)
    
    hasNoneGreaterThan10 = numbers.none( num -> num > 10 )
    // Returns: true (no numbers greater than 10)
    
    // More complex example with multiple conditions
    products = [
        { name: "laptop", price: 999, category: "electronics" },
        { name: "book", price: 15, category: "education" },
        { name: "phone", price: 599, category: "electronics" }
    ]
    
    // BIF: Check if none are free products
    hasNoFreeProducts = arrayNone( products, product -> product.price == 0 )
    
    // Member method: Check if none are luxury items (over $2000)
    hasNoLuxuryItems = products.none( product -> product.price > 2000 )
    fruits = "apple,banana,cherry,date"
    
    // Using BIF with lambda notation
    hasNoZFruits = listNone( fruits, fruit -> left( fruit, 1 ) == "z" )
    // Returns: true (no fruits start with 'z')
    
    // Using member method with lambda notation
    hasNoZFruits = fruits.none( fruit -> left( fruit, 1 ) == "z" )
    // Returns: true (no fruits start with 'z')
    users = queryNew( "name,age,status", "varchar,integer,varchar", [
        [ "Alice", 25, "active" ],
        [ "Bob", 30, "active" ],
        [ "Charlie", 35, "inactive" ]
    ] )
    
    // Using BIF: Check if none of the users are minors
    hasNoMinors = queryNone( users, row -> row.age < 18 )
    // Returns: true (no users under 18)
    
    // Using member method: Check if none have empty names
    hasNoEmptyNames = users.none( row -> len( trim( row.name ) ) == 0 )
    // Returns: true (all users have names)
    config = {
        database: "mysql",
        port: 3306,
        ssl: true,
        timeout: 30
    }
    
    // Using BIF: Check if none of the values are null or empty
    hasNoEmptyValues = structNone( config, ( key, value ) -> isNull( value ) || value == "" )
    // Returns: true (all config values are populated)
    
    // Using member method: Check if none of the keys contain "password"
    hasNoPasswordKeys = config.none( ( key, value ) -> findNoCase( "password", key ) > 0 )
    // Returns: true (no password-related keys found)
    # Example GitHub Actions step to verify BoxLang binary integrity
    - name: Verify BoxLang Binary
      run: |
        wget https://downloads.boxlang.io/boxlang-1.3.0.jar.sha256
        sha256sum -c boxlang-1.3.0.jar.sha256
        echo "Binary integrity verified ✓"
    : Returns a secure input hash of the given string using the BCrypt hashing algorithm.( Alias:
    GenerateBCryptHash
    )
  • BCryptVerify: Performs a BCrypt verification on the given string against the hashed value. ( Alias: BCryptCheckHash )

  • SCryptHash: Returns a secure input hash of the given string using the SCrypt hashing algorithm.( Alias: GenerateSCryptHash )

  • SCryptVerify: Performs a SCrypt verification on the given string against the hashed value. ( Alias: SCryptCheckHash )

  • GeneratePBKDFKey: Generates a PDFK key from the given password and salt.

  • ofFunction( context, function/closure/lambda ):Attempt - Produce a new attempt with a closure or lambda.
  • isEmpty():boolean - Is the value falsey or null

  • isPresent():boolean - Is the value present

  • ifPresent( consumer ):Attempt - Call the consumer lambda/closure if the value is present

  • ifPresentOrElse( consumer, action ):Attempt - Call the consumer lambda/closure if present or the action lambda/closure if not.

  • ifEmpty( consumer ):Attempt - Call the consumer if the value is not present

  • or( supplier ):Attempt - If the value is present it returns itself, if not, it calls the supplier closure/lambda to produce a new attempt.

  • orElse( other ):any- Get the value if present, or otherwise return the other value passed

  • orElseGet( supplier ):any - Get the value if present, otherwise call the supplier closure/lambda to produce the value you want to return.

  • map( mapper ): Attempt - Maps the value of the attempt if it exists, else returns the same attempt with no value.

  • filter( predicate ) - If the value is present it will call your predicate closure/lambda so you can run tests on the value. If the return is true it will return the same attempt, else an empty attempt.

  • orThrow():any - Returns the value if it exists or throws an exception

  • orThrow( message ):any - Returns the value if it exists or throws an exception with your custom message

  • orThrow( exception ):any - Returns the value if it exists or throws your custom exception

  • stream():Stream - If the value exists returns a stream with the value else an empty stream

  • toString():String - Gives you a string representation of the value

  • isValid():Boolean - If the value is present it will try to validate it with the registered validation schemas, if any.

  • toBeValid( closure or lambda ):Attempt - This allows you to register a lambda/closure to validate the data if any. When calling isValid() it will call this function if registered.

  • toBeBetween( min, max ):Attempt - This allows you to register a min and max numerical values to test the value. It must be in range to be valid.

  • toMatchRegex( regex ):Attempt - This allows you to register a regular expression to match against the value.

  • DES

  • DESede

  • HmacMD5

  • HmacSHA1

  • HmacSHA224

  • HmacSHA256

  • HmacSHA384

  • HmacSHA512

  • HmacSHA3-224

  • HmacSHA3-256

  • HmacSHA3-384

  • HmacSHA3-512

  • BL-231
    BL-235
    BL-241
    BL-245
    BL-246
    BL-247
    BL-248
    BL-249
    BL-250
    BL-257
    BL-263
    BL-265
    BL-266
    BL-270
    BL-128
    https://forgebox.io/view/bx-password-encrypt
    BL-251
    BL-258
    BL-260
    BL-264
    BL-268
    BL-269
    BL-271
    BL-272
    BL-274
    BL-275
    What Makes 1.2 Special

    BoxLang 1.2 isn't just another incremental update—it's a performance powerhouse packed with developer-friendly enhancements. We've implemented over 30 targeted optimizations across the runtime, from string operations and file handling to function invocations and memory management. These improvements mean your applications will run faster and more efficiently, often without requiring any changes to your existing code.

    Headline Features

    Maven Home Integration

    Enhanced Java Integration: The new Maven pom.xml support for BoxLang Home opens up seamless integration with the entire Java ecosystem, making it easier than ever to leverage existing Java libraries in your BoxLang applications. You can now add any Java dependencies in your BoxLang Home's pom.xml run mvn install and your runtime will be seeded with all the Java Libraries your application needs!

    Advanced Logging Control: Take complete control of your application's logging with new encoder options (text or json) and flexible appender choices between file and console output. Your logs, your way. You can also now chose between a file or console appender in all of your configuration files.

    Developer Experience: From nested grouped output support to the new BoxModuleReload() function for testing workflows, we've focused on making your development process smoother and more productive.

    Performance at the Core

    This release includes extensive performance optimizations that touch nearly every aspect of the runtime:

    • Optimized Hot Code Paths: Critical operations like string comparisons, numeric casting, and function invocations have been streamlined

    • Smarter Caching: From configuration lookups to file path resolution, we've added intelligent caching where it matters most

    • Reduced Overhead: Eliminated unnecessary operations in frequently-called code, including regex optimizations and stream-to-loop conversions

    • Memory Efficiency: Improved struct operations, hash encoding, and object creation patterns

    Compatibility & Stability

    We've strengthened BoxLang's compatibility with existing CFML codebases through numerous fixes and enhancements, including better date/time handling, improved query parameter support, and enhanced file operations. Whether you're migrating existing applications or building new ones, BoxLang 1.2 provides a more stable and predictable foundation.

    Ready to Upgrade

    BoxLang 1.2 includes 50+ improvements and bug fixes that enhance stability, performance, and developer experience. From small quality-of-life improvements to significant runtime optimizations, this release delivers value across the board.

    The combination of new features, performance enhancements, and rock-solid stability makes BoxLang 1.2 our most compelling release yet. Whether you're building high-performance web applications, integrating with Java ecosystems, or modernizing legacy CFML code, BoxLang 1.2 provides the tools and performance you need to succeed.

    Download BoxLang 1.2 today and experience the difference that thoughtful optimization and feature development can make.

    New Features

    • BL-1453 Maven pom.xml for the BoxLang Home so you can integrate with any Java library

    • BL-1464 implement nested grouped output/looping

    • BL-1474 Logger appenders in the boxlang.json can now chose their own encoder: text or json

    • BL-1476 Added ability for loggers to chose between file and console appenders

    • new event ON_FUNCTION_EXCEPTION

    • Update the error template to include a section where the user can contact us if the error is not good enough or we can improve it.

    Improvements

    • BL-1393 Add executionTime to result object of bx:http

    • BL-1397 FileCopy( source, targetDirectory ) when using a target directory doesn't work on BoxLang but works on Lucee

    • BL-1400 File bifs have too many casts, do one cast for performance

    • BL-1404 Add a unique request id metadata header when making requests in http so it can track easily

    • Add missing contexts to data interceptors

    • Add a `request` struct to the bxhttp result object

    • Add Allow Arguments to FileCopy and FileMove for granular extension security overrides

    • server.java.defaultLocale, server.java.availableLocales

    • New bif: BoxModuleReload( [name] ) to easily reload modules for testing purposes

    • optimize when LocalizationUtil string casts

    • optimize Struct.putAll()

    • optimize when basescope creates lockname to on demand

    • optimize string compare check for unicode

    • optimize case insensitive instanceof check

    • optimize isNumeric locale parsing and casting

    • optimize file detection/reading from disk unless needed

    • optimize getConfig() by caching at request context

    • Improve performance of string lowercasing and key creation

    • Only include source lines in exceptions when in debug mode

    • Optimize hash base 64 encoding

    • Optimize regex cache key generation

    • Move/Copy BIFs should all default to an overwrite value of true

    • Update the way loggers are setup and retrieved to avoid string and key lookups and accelerate the runtime

    • bif invocation interceptors missing the actual bif

    • BIF Interceptors hot code, only create events if they are states for it

    • order keys in struct dump alphabetically

    • DateTime and Duration Math Should Represent Fractional Days in Math Operations

    • Compat: DateAdd Should accept numeric fractional days as date argument

    • Exclude javaparser and other debug libraries from final jar

    • Optimize FQN class by removing regex usage in hot code

    • optimize generated setter by caching resolved file path

    • Optimize dynamic object by converting stream to loop in hot code

    • optimize output check by caching recursive lookups

    • optimize isEmpty code paths

    • optimize getting function enclosing class by caching

    • optimize number caster true/false string checks

    • optimize BoxStructSerializer class by avoiding struct.entrySet()

    • optimize string compare by removing unnecessary string to lower case

    • Update to use StatusPrinter2 from deprecated StatusPrinter using LogBack

    • Speed improvements for function invocation on hot code

    • Better handle low level parsing errors like java.util.EmptyStackException

    • Improve error messages when registering interceptors using the registration bifs when sending things other than interceptors

    • Add function name to interceptor data for ease of use

    • Accelerate dynamic object method handle executions

    Bugs

    • BL-1356 postBIFInvocation event

    • BL-1357 Simple preFunctionInvoke interceptor throws errors due to recursing into itself

    • BL-1385 Module that defines an interceptor has to specify "too much" for the class path

    • BL-1386 ModuleService reload and reloadAll() methods to provide ability for module reloading on development

    • forgot to populate the `populateServerSystemScope` from the override boxlang.json

    • isValid Boolean Returning Incorrect Result on Struct

    • Move default disallowed file extensions to web support and keep CLI open

    • Compat: CreateTime Should Support 0 hour argument

    • FileSystemUtil not absoluting paths when checking existence

    • `replaceNoCase` does not handle `null` strings like Lucee or ACF

    • http not using the user agent if passed by the user

    • Compat: add `server.coldfusion.supportedLocales`

    • Add Application.bx/cfc support for overriding allowed and disallowed extensions

    • this.logger is null in when getting an attempt() from a box future

    • Compat: Support ACF/Lucee `blockedExtForFileUpload` Application Setting

    • parameterized QoQ with maxLength errors

    • function dump template doesn't work in compat

    • CF transpiler not turning off accessors for child classes

    • getPageContext().getRequest() has no getScheme()

    • empty file fields in forms throw error on submit

    • Boxlang does not pickup custom tags that are in the same folder as the file that calls them

    • Compat: DateDiff should support fractional days as date argument

    • when doing a boxlang {action} command it should break and execute

    • Custom tag search is case-sensitive

    • inline annotation errors when literal value is a negative number

    • parser errors on class annotation called abstract

    • self-closing defaultcase tag not parsing

    • if you use options or params that include file extensions, the runner explodes

    • cfqueryparam tag not allowed outside of cfquery tag

    • Building query fails when part of the query is build inside function that outputs directly

    • query escaping of single quotes only escapes the first one, not all

    • `this.sessionStorage` assignment with Application-defined cache throws error.

    • Errors within application startup leave app in unusable state

    • Compat: Error thrown in QueryCompat interception when null param is encountered

    • calling java method with invoke() and no args fails

    • filewrite operations on existing files were not truncating it and leaving content behind.

    • isSimpleValue doesn't work with Keys

    Logo
    fruits = [ "apple", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn" ];
    result = fruits
      .parallelStream()
      .filter(  fruit -> fruit.startsWith( "a" ) )
      .toList();
      
      
    // Call a Java class that accepts a Runnable lambda with a BoxLang lambda
    myJavaclass.runAsync( () -> "Hello from BoxLang" )
    // Call a Java class that accepts a Runnable lambda with a BoxLang closure
    myJavaclass.runAsync( () => processMyClosureData() )
    import java.util.concurrent.CompletableFuture
    
    // Build out an async BoxLang task using native Java Interop
    function main( args = [] ) {
        // Define closures to fetch data from APIs 
        // (can be replaced with actual API calls)
        data1Future = CompletableFuture.supplyAsync( () => simulateApiCall("API 1") )
        data2Future = CompletableFuture.supplyAsync( () => simulateApiCall("API 2") )
    
        // Combine futures (waits for both to complete)
        // With a BoxLang lambda
        data1Future.thenAcceptBoth( data2Future, (data1, data2) -> {
            println("Data from API 1: " + data1);
            println("Data from API 2: " + data2);
            println("Combined data: " + data1 + " " + data2);
        });
    
        // Wait for all futures to complete
        CompletableFuture.allOf( data1Future, data2Future ).get();
    }
    
    private static simulateApiCall( apiName ) {
        try {
            sleep(1000); // Simulate API call delay
            println("Fetching data from " + apiName);
            return "Data from #apiName#"
        } catch (InterruptedException e) {
            println( e )
        }
    }
    result = fruits
      .parallelStream()
      .filter(  fruit -> fruit.startsWith( "a" ) )
      .toList();
    attempt( userService.get( rc.id ).isLoaded() )
        .ifPresent( user -> populate( user ).save() )
        .orThrow( "UserNotFoundException" )
        
    // A delayed attempt
    userDataAttempt = attempt( () -> userData.getData() )
        .toMatchRegex( "^myRegex" )
    
    ....
    
    return userDataAttempt
        .orElse( "" )
        
    /**
     * My Person 
     */
    @jsonExclude "anotherprop, anotherProp2"
    class Person{
    
    	property String name;
    	property String surname;
    	property numeric age;
    	property Date createdDate;
    	property Date modifiedDate;
    	property boolean isActive;
    	property Array tags;
    	@jsonExclude
    	property any javaSystem;
    	property anotherProp;
    	property anotherProp2;
    
    	function init(){
    		variables.name = "John";
    		variables.surname = "Doe";
    		variables.age = 30;
    		variables.createdDate = now();
    		variables.modifiedDate = now();
    		variables.isActive = true;
    		variables.tags = ["tag1", "tag2"];
    		variables.test = CreateObject( "java", "java.lang.System" );
    		variables.anotherProp = "hello";
    		variables.anotherProp2 = "hello";
    
    		return this;
    	}
    
    	function sayHello(){
    		return "Hello " & variables.name;
    	}
    
    }
    
    function main( args={} ){
        return new Person()
            .setName( "Luis" )
            .setSurname( "Majano" )
            .toJSON()
    }
    boxRegisterInterceptor( ()=> listenToRequestStarts(), "onServerScopeCreation" )
    boxRegisterRequestInterceptor( ()=> listenToRequestStarts(), "onRequestStart" )
    fruits = [ "apple", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn", "banana", "cherry", "ananas", "elderberry", "apricot", "avocado", "almond", "acorn" ];BL-277 implements BIFs GenerateSecretKey, Encrypt, Decrypt
    
    writeoutput( fruits )
    writeOutput( server )
    mvn install
    BL-1482
    BL-1485
    BL-1405
    BL-1406
    BL-1417
    BL-1419
    BL-1420
    BL-1421
    BL-1422
    BL-1423
    BL-1424
    BL-1425
    BL-1426
    BL-1427
    BL-1428
    BL-1429
    BL-1433
    BL-1434
    BL-1435
    BL-1436
    BL-1437
    BL-1438
    BL-1439
    BL-1443
    BL-1445
    BL-1446
    BL-1450
    BL-1454
    BL-1455
    BL-1456
    BL-1457
    BL-1458
    BL-1459
    BL-1460
    BL-1461
    BL-1462
    BL-1473
    BL-1481
    BL-1486
    BL-1489
    BL-1490
    BL-1493
    BL-1394
    BL-1396
    BL-1398
    BL-1399
    BL-1401
    BL-1402
    BL-1403
    BL-1409
    BL-1412
    BL-1414
    BL-1416
    BL-1418
    BL-1431
    BL-1432
    BL-1441
    BL-1442
    BL-1444
    BL-1447
    BL-1449
    BL-1451
    BL-1452
    BL-1463
    BL-1466
    BL-1467
    BL-1468
    BL-1469
    BL-1470
    BL-1475
    BL-1477
    BL-1479
    BL-1483
    BL-1484
    BL-1488

    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

    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:

    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

    You can learn more about virtual threads here:

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

    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:

    You can find the scheduler API Docs here:

    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.

    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.

    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.

    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

    Release Notes

    Improvements

    Command to schedule Schedulers: boxlang schedule {path.bx}

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

    this.schedulers for Application.bx loading of schedulers

    Scheduler BIFS for managing schedulers programmatically

    configuration for `schedulers` in the `boxlang.json`

    Add parser methods to report on and clear ANTLR cache

    this.moduleDependencies for Modules so they can activate module dependencies

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

    Added Liberica JDK as a supported version of our language

    Add HttpVersion key to http component

    add missing "hex" validation to isValid()

    executorGet() with no params must return the default executor

    Allow throw; with no expression

    change listener improvements

    Support @module-name suffix for class loading

    missing bifs: BoxUnregisterInterceptor(), BoxUnregisterRequestInterceptor()

    Added isVirtual, isDaemon, threadGroup, id to the thread metadata

    Threading Improvements: isThreadAlive(), isThreadInterrupted(), threadInterrupt() bifs

    modules directories being created unecesarrily if not found

    enable transparent anchors in java regex

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

    Add Virtual Attribute to Thread Component

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

    Put debug mode cache clearing behind a config flag: clearClassFilesOnStartup

    Make Java interop varargs optional

    only populate form.fieldNames on POST method

    Add `modules` key to server.boxlang struct

    Add `BoxCache` annotation to allow aliasing cache providers

    Bugs

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

    cliRead adds a line break

    Dump of XML Object Does not Include Node Names

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

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

    BoxLang BIF Proxy losing context of execution

    Key instance not being coerced to string

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

    Static method calling static method loses static context

    application.applicationName is a Key instance, not a string

    GetContextRoot Returning Slash-Prefixed Root

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

    access remote not recognised

    Unable to compile/call box class with java override

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

    Compat: reMatchNoCase should find matches but generates error

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

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

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

    Space missing when cfquery in function

    bx:zip doesn't implement result

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

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

    CGI Scope should check variable name before attempting http_header_name convention

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

    Invoke BIF No Longer Functioning on Java Objects in Compat mode

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

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

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

    ClassMetaDataVisitor cannot find super class in same directory

    cfhttp port attribute is not supported

    servlet runtime using wrong getPageContext() BIF

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

    directoryList has odd behavior when using 'dot' paths

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

    Error in cfdump when dumping a xml variable

    Array Index Assignment for appending XML Children Not Working

    class java.lang.Integer cannot be cast to class java.lang.String

    Error serializing to JSON

    getPageContext Lucee compatibility

    DateConvert BIF Not Locale Aware

    cftransaction - Failed to set savepoint

    Can't cast [] to a DateTime

    Illegal class name

    ListToArray on a Null value Throws Exception

    ReplaceNoCase with Integer Replacement throws Exception

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

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

    current template not set in static initializer block

    apparent connection leak detected

    Issue with Java interop and var args

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

    Modify dump when dumping a class instance

    Default cache was not being defaulted

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

    system cache clear now can clear query caching

    Cache Component Not Accepting Timespan Timeout and IdleTime Args Correctly

    Replace BIF fails when replacement argument is numeric

    cfcatch key detail is missing

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

    class java.lang.Integer cannot be cast to class java.lang.String

    Invoke Throws Error When Null Value is Assigned on Generated Setter

    Consider renaming jsonDeserialize member function

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

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

    Unsupported isolation level: READ_COMMITTED

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

    1.0.0-Beta6

    July 19, 2024

    BoxLang Betas are released weekly. This is our fifth beta marker. Here are the release notes.

    New Features

    BL-157 Implement nested transactions

    We are excited to bring the completion of nested transactions into BoxLang, something we have wanted in an open-source engine for years.

    Here, the INSERT in the child transaction is rolled back, but the parent transaction's INSERT statement persists.

    General behavior:

    • A rollback on the parent transaction will roll back the child transaction.

    • A rollback on the child will NOT roll back the parent.

    • Child transaction savepoints use a prefix so they don't collide with the parent transaction.

    • Logging has been added, so you can easily see the transaction lifecycle as a transaction is created, savepoints are created, transactions rollback, etc.

    Transaction events will come in the next beta.

    queryReverse() finalized

    This BIF is now complete so you can easily reverse query data.

    Allow servlet to expand paths so CommandBox web aliases or ModCFML web dirs can be used and new OnMissingMapping event.

    Adobe CFML Engines do this today via their “magic” connector. Lucee has never supported it. The expanded path should work like so now:

    • if it doesn’t start with a / (and isn’t absolute), then make it relative to the base path

    • look for a BoxLang mapping (not including “/” )

    • Check if it’s an absolute path already, like C:/foo/bar

    • Then announce an ON_MISSING_MAPPING

    The servlet runtime will have a listener for ON_MISSING_MAPPING that attempts to use servetContext.getRealPath() to try and resolve the path. This will allow any aliases in the resource manager to kick in.

    If the servlet has an alias called /foo and you expand the path /foo/existingFile.txt, it will see it, but if you expand the path /foo/notExistingFile.txt then it will not “see” the mapping. We can solve that by taking off segments to see if any part of the path is found, but there is a performance hit to that, and I’m not sure if it’s necessary or not.

    Allow static functional access to BIFs

    We have introduced static access to headless BIFS in BoxLang so you can use them as method references anywhere a BIF can be received, EVEN in Java classes that implement similar BIFS.

    This expression represents a first-class BoxLang function that can be invoked directly.

    You can also store the BIF static access into variables.

    You can also leverage it as a high-order function combination from methods or classes that expect function references.

    Allow Functional binding to member functions

    In order to explain this new functionality in BoxLang, here is a Java snippet:

    This syntax is a shortcut for writing out the following Java lambda:

    (Other JVM languages like Clojure have similar syntax) The String::toUpperCase binds to the instance method toUpperCase, but in a way that it will be called on each string instance in the stream. So for each iteration, it will call the toUpperCase method on that instance. Nothing like this ever existed in CFML engines. However, in BoxLang, it does now. BoxLang allows you to do the following:

    • BoxLang-type member methods

    • Class member methods

    • Java member methods

    • Any object member/field

    Since member methods in BoxLang aren’t necessarily bound to a class and we’re a dynamic language, we have simplified the syntax to this:

    This is a function expression that accepts a single argument and calls the method name specified on the incoming instance, returning the result of the member call. it is a shortcut for

    So our Java example becomes like this in BoxLang

    When not using (), check if there is a field of that name that is not a function, and if so, return that field value. So, the following example would fetch the name key in the struct.

    If the syntax .foo() is used or there is no field of that name, then it will be assumed we’re invoking a method. It can be directly invoked:

    It can be placed into a variable and invoked later:

    And it can be passed to higher-order functions. (This is the main use case)

    Additionally, we have added support for multiple-arguments as well:

    Example:

    The arguments will not be evaluated until the function is invoked, and the argument expressions will be re-evaluated for every invocation.

    The argument evaluation will have lexical binding to the declaring context.

    or

    Bound member methods can also use named params (unless they are Java methods, of course)

    This brings a whole new dimension of dynamic goodness for not only BoxLang functions but also for Java functions. Welcome to a new era!

    arrayRange() BIF to create arrays with a specific range of values

    This is one of our very first steps in supporting range types. You know have the capability to generate arrays with a specific boxed range using arrayRange( from, to ). You can use a from and to numeric index, and it will build the array with that many elements with the range as its value. However, you can also use range notation: {from}..{to}

    threadTerminate() finalized

    We have now finalized a threadTerminate( name ) BIF.

    threadJoin() BIF Finalized

    We have now finalized a threadJoin( [name], timeout ) BIF. We have expanded this BIF and if you don't pass a thread name or a list of names, it will join all active threads.

    queryInsertAt() BIF finalized

    This is now finalized.

    QueryRowSwap() bif finalized

    This is now finalized.

    runAsync() completed but based on the powerful new BoxFuture -> CompletableFuture

    This is a big ticket. Welcome to the future with BoxFuture. We have completed the ability to do asynchronous pipelines and parallel computations in BoxLang. We have introduced a new type called BoxFuture, which extends a Java Completable Future. The return of a runAsync() is a BoxFuture, and you can create pipelines to process the computations. You can access all the methods in a Completable future and many more. This will be documented in our guide.

    Futures

    You have a new BIF: futureNew( [value], [executor] ) that can create new box futures. By default it will create incomplete and empty futures. However, you can pass different values to the future. Check out the API Docs:

    • value : If passed, the value to set on the BoxFuture object as completed, or it can be a lambda/closure that will provide the value, and it will be executed asynchronously, or it can be a native Java CompletableFuture

    • executor : If passed, it will use this executor to execute the future. Otherwise, it defaults to the fork/join pool in Java.

    runAsync( callback, [executor ] )

    You can pass a closure or lambda to runAsync() to execute it asynchronously. The seconds parameter is an executor which runs the threads. It runs in the fork/join pool by default, but you can also pass your own executors. The return is a BoxFuture, which you can then do asynchronous pipelines.

    BIF Collection for managing and interacting with async service executors: list, get, has, new, shutdown

    You now have the full capability to register, create, and manage custom executors in BoxLang. The AsyncService manages all executors in BoxLang.

    Here are the new functions dealing with executors:

    • executorGet( name ): Get a registered executor

    • executorHas( name ): Checks if an executor has been registered or not

    • executorList() : Lists all registered executors

    The available executor types are:

    • cached - Creates a cached thread pool executor.

    • fixed - Creates a fixed thread pool executor.

    • fork_join - Creates a fork-join pool executor.

    Configuration now supports executor registration for global usage

    You can now register your executors globally in BoxLang in the boxlang.json

    Implement primary/foreign key columns in dbInfo

    DBInfo now returns primary and foreign key columns when you need them.

    Implement QueryMeta class for $.bx.meta or $.bx.getMeta() debugging support

    Metaprogramming on queries is now available with much more information like caching, execution status, records, etc.

    Improvements

    "Fix" return types of BIFs that return "true" for no real reason

    One of the odd things about CFML is the following:

    In BoxLang, the following BIFS returns the instance it was called with instead of a boolean. However, if you are in compat mode in a CFML file, you will get the old behavior.

    • arrayAppend()

    • arrayClear()

    • arrayDeleteAt()

    The following BIFs return something other than the original data structure, but they have a good reason for doing so, so they remain as is:

    • queryAddColumn() -- returns index of the column removed

    • queryAddRow() -- returns the row number added

    The following BIF returns the query in Adobe, which we’ll match. Lucee returns the array of removed data, but we’re ignoring that since we agree with Adobe’s behavior.

    • QueryDeleteColumn()

    Provide Java FI typing on all higher-order BIFs

    make name un-required in the application component

    DynamicObject equals() hashCode() to allow for dynamic checking

    Bugs

    Overridden getter in parent class not being used

    List and Delmiter Args are not correct in ListReduce callback

    The throwable Dump table is not styled

    FORGEBOX: Boxlang Redis Moduleforgebox.io
    Attempt (boxlang 1.0.0-beta2 API)s3.amazonaws.com

    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

  • https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html
    https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-rc.3/ortus/boxlang/runtime/async/tasks/BaseScheduler.html
    BL-1262
    BL-1265
    BL-1269
    BL-1268
    BL-1264
    BL-1212
    BL-1207
    BL-1170
    BL-1171
    BL-1172
    BL-1176
    BL-1181
    BL-1182
    BL-1183
    BL-1193
    BL-1195
    BL-1196
    BL-1197
    BL-1206
    BL-1208
    BL-1209
    BL-1239
    BL-1240
    BL-1251
    BL-1258
    BL-1259
    BL-1260
    BL-1263
    BL-1023
    BL-1083
    BL-1107
    BL-1145
    BL-1154
    BL-1162
    BL-1163
    BL-1164
    BL-1165
    BL-1166
    BL-1168
    BL-1169
    BL-1174
    BL-1175
    BL-1177
    BL-1178
    BL-1179
    BL-1185
    BL-1187
    BL-1188
    BL-1189
    BL-1191
    BL-1192
    BL-1198
    BL-1200
    BL-1201
    BL-1202
    BL-1203
    BL-1204
    BL-1205
    BL-1210
    BL-1211
    BL-1213
    BL-1215
    BL-1220
    BL-1221
    BL-1222
    BL-1223
    BL-1224
    BL-1225
    BL-1226
    BL-1227
    BL-1228
    BL-1229
    BL-1230
    BL-1231
    BL-1232
    BL-1233
    BL-1234
    BL-1236
    BL-1237
    BL-1238
    BL-1241
    BL-1242
    BL-1243
    BL-1244
    BL-1245
    BL-1246
    BL-1247
    BL-1248
    BL-1249
    BL-1250
    BL-1252
    BL-1255
    BL-1256
    BL-1257
    BL-1261

    You can't change any transaction properties on a nested transaction. i.e., once the parent transaction begins, you can't begin a child transaction and change the isolation level.

    interception point
  • if no interceptor provided a value, then resolve via the root / mapping

  • executorNew( name, type, [maxThreads:20] ): Creates and registers an executor by type and max threads if applicable.
  • executorShutdown( name ): Shuts down an executor

  • executorStatus( [name] ): Get a struct of executor metadata and stats by name or all.

  • scheduled - Creates a scheduled thread pool executor.
  • single - Creates a single thread executor.

  • virtual - Creates a virtual thread executor.

  • work_stealing - Creates a work-stealing thread pool executor.

  • arrayInsertAt()
  • arrayResize()

  • arraySet()

  • arraySwap()

  • StructClear()

  • StructKeyTranslate()

  • StructInsert()

  • structAppend()

  • QuerySetRow()

  • QueryDeleteRow()

  • QuerySort()

  • ArrayPrepend()

  • BL-348
    BL-349
    BL-350
    BL-351
    BL-352
    BL-353
    BL-354
    BL-355
    BL-356
    BL-358
    Async Programming
    https://s3.amazonaws.com/apidocs.ortussolutions.com/boxlang/1.0.0-beta6/ortus/boxlang/runtime/async/BoxFuture.html
    BL-359
    BL-360
    BL-124
    BL-255
    BL-357
    BL-366
    BL-371
    BL-346
    BL-364
    BL-370
    BL-365
    install-bx-module bx-orm
    "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
    	}
    },
    threadNew( 
      runnable: () => {},
      virtual: true
    )
    
    bx:thread name="virtualTest" virtual=true{
      // A virtual thread.
    }
    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" ) );
    	}
    
    }
    boxlang schedule MyScheduler.bx
    "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": {}
    },
    class{
    
        ...
        
        this.schedulers = [ "path.to.Scheduler" ]
    
    }
    transaction{
      queryExecute( "INSERT INTO developers ( id, name, role ) VALUES ( 22, 'Brad Wood', 'Developer' )", {} );
        
        transaction{
          queryExecute( "INSERT INTO developers ( id, name, role ) VALUES ( 33, 'Jon Clausen', 'Developer' )", {} );
    	 transactionRollback();
        }
        
    }
    // Syntax
    ::BIF
    
    // Examples
    ::UCase
    ::hash
    (::reverse)( "darb" ); // brad
    foo = ::ucase
    foo( "test" ) // TEST
    ["brad","luis","jon"].map( ::ucase ); // [ "BRAD","LUIS","JON" ]
    
    [1.2, 2.3, 3.4].map( ::ceiling );    // [2,3,4]
    
    ["brad","luis","jon"].map( ::hash ); // ["884354eb56db3323cbce63a5e177ecac", "502ff82f7f1f8218dd41201fe4353687", "006cb570acdab0e0bfc8e3dcb7bb4edf" ]
    List.of("apple", "banana", "cherry").stream().forEach(String::toUpperCase);
    List.of("apple", "banana", "cherry").stream().forEach(str -> str.toUpperCase());
    .methodName
    i -> i.methodName()
    ["apple", "banana", "cherry"].stream().forEach( .toUpperCase );
    nameGetter = .name
    data = { name : "brad", hair : "red" }
    nameGetter( data ) // brad
    (.reverse)( "darb" ); // brad
    foo = .ucase;
    foo( "test" );  // TEST
    ["brad","luis","jon"].map( .toUpperCase ); // ["BRAD","LUIS","JON"]
    
    [1.2, 2.3, 3.4].map( .ceiling ); // [2,3,4]
    
    [
      { myFunc : ()->"eric" },
      { myFunc : ()->"gavin" }
    ].map( .myFunc ) // [ "eric", "gavin" ]
    .methodName( arg1, arg2 )
    ["brad","luis","jon"].map( .left(1) ); // [ "b", "l", "j" ]
    pendingOrders.each( .submit( generateNextOrderNumber() ) ) // Fresh order number for each submission
    local.suffix = " Sr."
    ["brad","luis","jon"].map( .concat( suffix ) ); // [ "brad Sr.", "luis Sr.", "jon Sr." "]
    children.each( .setParent( this ) )
    foo = .left( count=2 );
    foo( "test" ); // "te"
    // an array from 1 to 100
    a = arrayRange( "1..100" )
    a = arrayRange( 1, 100 )
    
    // a negative indexed array
    a = arrayRange( "-10..10" )
    a = arrayRange( -10, 10 )
    // incomplete future
    f = futureNew()
    
    // completed future with a value
    f = futureNew( myValue )
    
    // a future that executes an asynchronous lambda/closure and the value will be the result
    f = futureNew( () -> orderService.calculate() )
    
    // A future with an executable and a virtual thread executor
    f = futureNew(
        () -> processTasks(),
        executorNew( "virtual", "virtual" )
    )
    calculation = runAsync( () -> calculateNumber() )
        .then( result -> result * 2 )
        .then( result -> result + 5 )
        .onError( exception -> { manage exception } )
        .get()
        
    
    // Use a custom executor
    runAsync( () -> "Hello", executorNew( "single", "single" ) )
        .then( ::println )
        .join()
        
    // Process an incoming order
    runAsync( () => orderService.getOrder() )
        .then( order => enrichOrder( order ) )
        .then( order => performPayment( order ) )
        .thenAsync( 
            order => dispatchOrder( order ), 
            executorNew( "cpuIntensive", "fixed", 150 )
         )
        .then( order => sendConfirmation( order ) );
     
    // Combine Futures
    var bmi = runAsync( () => weightService.getWeight( rc.person ) )
        .thenCombine(
    	runAsync( 
    	    () => heightService.getHeight( rc.person ) ),
                ( weight, height ) => {
                var heightInMeters = arguments.height/100;
                return arguments.weight / (heightInMeters * heightInMeters );
                })
            .get();   
    // Global Executors for the runtime
    // These are managed by the AsyncService and registered upon startup
    // The name of the executor is the key and the value is a struct of executor settings
    // Types are: cached, fixed, fork_join, scheduled, single, virtual, work_stealing
    // The `threads` property is the number of threads to use in the executor. The default is 20
    // Some executors do not take in a `threads` property
    "executors": {
    	"boxlang-tasks": {
    		"type": "scheduled",
    		"threads": 20
    	},
    	"cacheservice-tasks": {
    		"type": "scheduled",
    		"threads": 20
    	}
    },
    myArr.append( "foo" ) // returns myArr
    arrayAppend( myArr ) // returns true??
    Logo

    1.5.0

    August 30, 2025

    We're excited to announce BoxLang 1.5.0, bringing significant improvements to performance, reliability, and developer experience. This release focuses on enhanced AWS Lambda support, better Java interoperability, improved query handling, and numerous bug fixes that make BoxLang more robust for production workloads.

    🚀 Major Highlights

    AWS Lambda Runtime Enhancements

    BoxLang 1.5.0 introduces powerful optimizations for serverless deployments, including class caching, connection pooling, and performance metrics.

    Enhanced Query Operations

    Improved support for multiple SQL statements, better parameter handling, and enhanced metadata capture for database operations.

    Advanced Java Interop

    Better method resolution for overloaded Java methods and improved handling of primitive type expectations.


    🏗️ AWS Lambda Runtime Features

    Lambda Class Caching

    Ticket:

    BoxLang now caches compiled lambda classes to avoid expensive recompilations on subsequent invocations, dramatically improving cold start performance.

    Configurable Connection Pooling

    Ticket:

    Control AWS runtime connection pool size via the new environment variable:

    Performance Metrics Logging

    Ticket:

    Enable detailed performance metrics in debug mode to monitor Lambda execution times and resource usage.

    Convention-Based URI Routing

    Ticket:

    Automatic routing using PascalCase conventions. You can now build multi-class Lambda functions with BoxLang easily following our conventions.


    🔧 Core Runtime Improvements

    Enhanced File Upload Support

    Tickets: ,

    FileUpload now includes blockedExtensions argument and correctly populates file name properties:

    Improved Error Handling for Primitive Returns

    Ticket:

    Better error messages when proxied UDFs return null where primitives are expected:

    Memory Leak Prevention

    Ticket:

    Enhanced thread management prevents memory leaks with unbounded thread usage in long-running applications.

    Virtual Thread Support for Parallel Operations

    Ticket:

    All parallel BIFs now support a virtual argument to leverage Java's virtual threads for improved performance and resource efficiency. You can also pass it instead of the maxThreads argument as well.

    Performance Benefits:

    • Reduced Memory Footprint: Virtual threads use significantly less memory than platform threads

    • Better Scalability: Handle thousands of concurrent operations without thread pool exhaustion

    • Improved Throughput: Especially beneficial for I/O-bound operations like API calls or database queries

    Supported Methods:

    Type
    Methods

    📊 Database & Query Enhancements

    Multiple SQL Statement Support

    Ticket:

    QueryExecute now properly handles multiple SQL statements:

    Enhanced Generated Key Capture

    Ticket:

    Update Count Tracking

    Ticket:

    Improved Parameter Handling

    Ticket:

    Better handling of queries with both loose colons and positional parameters:


    🔗 Java Interoperability Improvements

    Better Method Resolution

    Ticket:

    Improved matching for overloaded Java methods:

    Ticket:

    Better preference handling when Java methods accept Object arguments:


    🏗️ CFML Compatibility Enhancements

    Script Custom Tag Support

    Ticket:

    Added support for Adobe ColdFusion script-based custom tags:

    Encrypted Datasource Password Support

    Ticket:

    Support for Lucee-style encrypted datasource passwords:

    Component Name Annotation Fix

    Ticket:

    The name annotation on components now correctly sets metadata without overwriting:


    🛠️ Developer Experience Improvements

    Enhanced List Functions

    Ticket:

    List BIFs now preserve custom delimiters when reassembling:

    Tickets: ,

    Duration objects can now be compared with integers and other numeric values:

    Class Metadata Enhancement

    Ticket:

    Box Class metadata now includes "output" key for better introspection:


    🐛 Notable Bug Fixes

    Query of Queries Parsing

    Ticket: Fixed parsing errors in Query of Queries when using parentheses in expressions.

    Super Reference Resolution

    Ticket: Corrected super reference resolution for mixin UDFs in parent classes.

    HTTP Header Handling

    Ticket: Resolved HTTP errors when Accept-Encoding and TE headers are set as HTTP parameters.

    Module Management

    Ticket: Fixed module unload process to properly remove and unregister module resources.

    Thread Context Handling

    Ticket: Ensured threads consistently use the correct context classloader.

    SQL Formatting

    Ticket: Fixed the sqlPrettify function for proper SQL formatting.


    📊 Performance & Reliability

    • Memory Usage: Reduced memory footprint through better thread management

    • AWS Cold Starts: Significant improvement through lambda class caching

    • Database Operations: Enhanced reliability with better error handling and connection management

    • Java Interop: More efficient method resolution and argument handling


    🔧 Configuration Updates

    Docker Environment Variables

    Ticket:

    Resolved collision between Docker env var BOXLANG_MODULES and the config modules key.

    Cache Settings

    Ticket:

    Cache settings now properly replaced by environment variables:


    ⚡ Migration Notes

    Breaking Changes

    • None in this release

    Deprecations

    • No new deprecations

    Recommended Updates

    1. AWS Users: Set BOXLANG_LAMBDA_CONNECTION_POOL_SIZE environment variable for optimal performance

    2. File Upload: Review code using fileUpload() to take advantage of new blockedExtensions security feature

    3. Module Developers: Test module loading/unloading if you experienced issues in 1.4.x


    Release Notes

    Improvements

    Bump org.semver4j:semver4j from 5.8.0 to 6.0.0.

    fileUpload missing blockedExtensions argument

    Better error if proxied UDF returns null where primitive is expected

    add "output" key to Box Class Meta

    Add `Virtual` Argument to BIF supporting parallel operations

    DynamicObject not unwrapping arguments passed to method

    Remove query column map from query metadata

    Prevent memory leak with unbounded thread usage

    Capture all generated keys

    Capture update counts

    AWS Runtime - Cache compiled lambda classes to avoid recompilations

    AWS Runtime - Add aws runtime pool configuration via new ENV variable: BOXLANG_LAMBDA_CONNECTION_POOL_SIZE which defaults to 2

    Bugs

    queryExecute multiple statements

    List BIFs which reassemble the list don't preserve delimiters

    queryExecute - cannot execute query containing loose ':' and positional parameters

    fileUpload: serverFileName, serverFile, clientFile, clientFileName are not correct per the spec

    Interop service when dealing with methods with `Object` arguments, would give preference to coercionable arguments. Ex: Formatter.format( BoxLang DateTime ) would fail

    Trying to load module class before module is registered errors

    duration can't compare against an integer

    Compare operator cannot cast Duration to Number

    JDBC - "driver not registered" log on engine startup despite being installed

    Miniserver: Docker env var BOXLANG_MODULES collides with modules key in config

    super reference incorrect for mixin UDF in parent class

    string caster not obeying fail flag when inputStream errors

    HTTP Error When Accept-Encoding and TE Headers are being set as HTTP Params

    Parsing error in QoQ with parentheses

    Missing support for ACF script custom tags

    Ignore extraneous return values from void proxies

    Usage of quoted operators fails to compile.

    sqlPrettify is broken

    CFML Compat - `name` annotation on Component overwrites the metadata name

    Threads not always using context classloader

    JDBC not handling raised errors

    Module unload fails to remove/unregister module resources

    Issues with numberFormat masks

    Cache settings do not get replaced by environment variables

    Java interop matching in correct overloaded methods

    New Features

    Add support for Lucee's encrypted datasource passwords in compat

    AWS Runtime - Log performance metrics when in debug mode

    AWS Runtime - URI Routing by convention using PascalCase: /products -> Products.bx, /home-savings -> HomeSavings.bx

    Array

    arrayEach(), arrayEvery(), arrayFilter(), arrayMap(), arrayNone(), arraySome()

    List

    listEach(), listEvery(), listFilter(), listMap(), listNone(), listSome()

    Query

    queryEach(), queryEvery(), queryFilter(), queryMap(), queryNone(), querySome()

    Struct

    structEach(), structEvery(), structFilter(), structMap(), structNone(), structSome()

    BL-1712
    BL-1716
    BL-1713
    BL-1714
    BL-1664
    BL-1663
    BL-1680
    BL-1697
    BL-1687
    BL-1186
    BL-1700
    BL-1701
    BL-1661
    BL-1715
    BL-1667
    BL-1679
    BL-1127
    BL-1684
    BL-1660
    BL-1669
    BL-1670
    BL-1686
    BL-1678
    BL-1674
    BL-1676
    BL-1705
    BL-1696
    BL-1683
    BL-1673
    BL-1709
    BL-1556
    BL-1664
    BL-1680
    BL-1686
    BL-1687
    BL-1688
    BL-1693
    BL-1697
    BL-1700
    BL-1701
    BL-1712
    BL-1716
    BL-1186
    BL-1660
    BL-1661
    BL-1663
    BL-1667
    BL-1668
    BL-1669
    BL-1670
    BL-1671
    BL-1673
    BL-1674
    BL-1675
    BL-1676
    BL-1678
    BL-1679
    BL-1681
    BL-1682
    BL-1683
    BL-1684
    BL-1696
    BL-1699
    BL-1705
    BL-1706
    BL-1709
    BL-1715
    BL-1127
    BL-1713
    BL-1714
    // Your BoxLang lambda handlers now benefit from automatic class caching
    function handler( event, context ) {
        // Compiled classes are cached automatically for faster subsequent invocations
        return {
            "statusCode" : 200,
            "body" : serializeJSON( processEvent( event ) )
        };
    }
    # Set connection pool size (defaults to 2)
    BOXLANG_LAMBDA_CONNECTION_POOL_SIZE=2
    // URL: /products -> Products.bx
    // URL: /home-savings -> HomeSavings.bx  
    // URL: /user-profile -> UserProfile.bx
    
    // Products.bx
    function handler( event, context ) {
        return {
            "statusCode" : 200,
            "body" : getProductCatalog()
        };
    }
    // Enhanced file upload with security
    result = fileUpload( 
        destination = "/uploads/", 
        fileField = "attachment",
        blockedExtensions = [ "exe", "bat", "com" ],
        allowedExtensions = [ "jpg", "png", "pdf", "docx" ]
    );
    
    // Correctly populated properties
    writeOutput( "Client filename: " & result.clientFile );
    writeOutput( "Server filename: " & result.serverFile );
    writeOutput( "Original name: " & result.clientFileName );
    writeOutput( "Saved as: " & result.serverFileName );
    // Before: Cryptic casting error
    // After: Clear error message
    function getScore() {
        return; // null return
    }
    
    numeric score = getScore(); // Now provides clear error about null->numeric conversion
    // Array operations with virtual threads
    largeNumbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
    
    // Use virtual threads for parallel processing
    results = arrayMap( largeNumbers, ( item ) => {
        // Simulate heavy computation
        sleep( 100 );
        return item * item;
    }, true, true ); // maxThreads=true => virtual=true
    
    // List operations with virtual threads  
    csvData = "apple,banana,cherry,date,elderberry";
    processed = listMap( csvData, ( item ) => {
        return uCase( item );
    }, ",", true, true ); // delimiter, maxThreads=true => virtual=true
    
    // Query operations with virtual threads
    users = queryNew( "id,name,email", "integer,varchar,varchar", [
        [ 1, "John", "[email protected]" ],
        [ 2, "Jane", "[email protected]" ],
        [ 3, "Bob", "[email protected]" ]
    ] );
    
    // Process query rows with virtual threads
    queryEach( users, ( row, index ) => {
        // Simulate API call or heavy processing
        validateEmail( row.email );
    }, true, true ); // maxThreads=true => virtual=true
    
    // Struct operations with virtual threads
    userPrefs = {
        "theme" : "dark",
        "language" : "en", 
        "notifications" : "enabled"
    };
    
    // Filter preferences with virtual threads
    activePrefs = structFilter( userPrefs, ( key, value ) => {
        return value != "disabled";
    }, true, true ); // maxThreads=true => virtual=true
    
    // Traditional vs Virtual Thread comparison
    // Traditional platform threads (limited by OS)
    results1 = arrayMap( data, processor, 10, false ); // 10 platform threads
    
    // Virtual threads (lightweight, managed by JVM)  
    results2 = arrayMap( data, processor, true, true ); // Auto threads, virtual=true
    // Execute multiple statements in a single call
    result = queryExecute( "
        UPDATE users SET last_login = NOW() WHERE id = :userID;
        INSERT INTO login_log (user_id, login_time) VALUES (:userID, NOW());
        SELECT * FROM users WHERE id = :userID;
    ", {
        "userID" : { value: 123, cfsqltype: "numeric" }
    } );
    // Capture all generated keys from INSERT operations
    result = queryExecute( "
        INSERT INTO orders (customer_id, order_date) 
        VALUES (:customerID, NOW())
    ", {
        "customerID" : { value: 456, cfsqltype: "numeric" }
    }, {
        result: "insertResult"
    } );
    
    // Access generated keys
    newOrderID = insertResult.generatedKey;
    writeOutput( "New order created with ID: " & newOrderID );
    // Track how many records were affected
    result = queryExecute( "
        UPDATE products 
        SET price = price * 1.10 
        WHERE category = :category
    ", {
        "category" : { value: "Electronics", cfsqltype: "varchar" }
    }, {
        result: "updateResult"  
    } );
    
    writeOutput( "Updated " & updateResult.recordCount & " products" );
    // Now works correctly with mixed parameter styles
    sql = "SELECT * FROM events WHERE start_time > '2024-01-01 00:00:00' AND user_id = ?";
    result = queryExecute( sql, [ 123 ] );
    // Java class with multiple format() methods
    formatter = createObject( "java", "java.text.DecimalFormat" ).init( "#,##0.00" );
    
    // Now correctly resolves the right overloaded method
    boxLangNumber = 1234.56;
    formatted = formatter.format( boxLangNumber ); // "1,234.56"
    // BoxLang DateTime objects now properly handled
    dateTime = now();
    javaFormatter = createObject( "java", "java.time.format.DateTimeFormatter" )
        .ofPattern( "yyyy-MM-dd HH:mm:ss" );
    
    // Now works correctly with BoxLang DateTime
    formatted = javaFormatter.format( dateTime );
    // CustomButton.cfc (custom tag)
    component {
        
        function onStart() {
            if ( !structKeyExists( attributes, "text" ) ) {
                attributes.text = "Click Me";
            }
            return true;
        }
        
        function onEnd() {
            writeOutput( '<button class="btn btn-primary">' & attributes.text & '</button>' );
            return true;
        }
    }
    
    // Usage in template
    bx:customButton text="Save Changes";
    // BoxLang.json datasource configuration
    {
        "datasources": {
            "myDB": {
                "driver": "mysql",
                "host": "localhost", 
                "database": "myapp",
                "username": "dbuser",
                "password": "encrypted:ABC123DEF456", // Encrypted password support
                "port": 3306
            }
        }
    }
    /**
     * @name CustomService
     * @description Provides custom business logic
     */
    component {
        // Component metadata.name is now correctly set to "CustomService"
        
        function init() {
            return this;
        }
    }
    // Custom delimiter is preserved
    originalList = "apple|banana|cherry";
    processedList = listSort( originalList, "text", "asc", "|" );
    // Result maintains "|" delimiter: "apple|banana|cherry"
    
    // Works with any delimiter
    csvData = "John,25,Engineer";
    sortedCsv = listSort( csvData, "text", "asc", "," );
    // Maintains comma delimiter
    timeout = createTimeSpan( 0, 0, 5, 0 ); // 5 minutes
    maxWait = 300; // 300 seconds
    
    // Now works correctly
    if ( timeout > maxWait ) {
        writeOutput( "Timeout exceeds maximum wait time" );
    }
    
    // Duration arithmetic with numbers
    newTimeout = timeout + 60; // Add 60 seconds
    metadata = getMetadata( myComponent );
    if ( metadata.output ) {
        writeOutput( "Component generates output" );
    }
    # Environment variables now correctly override cache settings
    BOXLANG_CACHE_DEFAULT_TIMEOUT=3600
    BOXLANG_CACHE_MAX_ELEMENTS=1000
    bxorm.ortusbooks.com
    BoxFuture (boxlang 1.0.0-beta6 API)s3.amazonaws.com

    1.8.0

    December 5, 2025

    BoxLang 1.8.0 is a massive release bringing revolutionary HTTP/SOAP capabilities, comprehensive CFML compatibility improvements, and critical stability enhancements. This release introduces a completely rewritten HTTP component with fluent APIs, streaming support, and persistent connection management, alongside a powerful SOAP/WSDL client for web service integration. With over 100 bug fixes and improvements, this release focuses on production-readiness, CFML migration compatibility, and modern web application development patterns.

    🚀 Major Highlights

    🎯 Modular Compiler Architecture & Ultra-Slim Runtime

    BoxLang 1.8.0 introduces a revolutionary modular compiler architecture that delivers unprecedented flexibility, security, and deployment efficiency for enterprise applications.

    🪶 Mega-Slim 7MB Runtime

    The BoxLang runtime has been dramatically optimized, dropping from over 9MB to just 7MB by removing the JavaParser compiler dependencies. This lean footprint provides:

    • 22% Smaller runtime for faster downloads and deployments

    • Reduced memory footprint for containerized environments

    • Faster startup times due to smaller classpath

    • Improved security surface with fewer dependencies

    🔐 Two Deployment Flavors for Enterprise Security

    BoxLang now ships in two distinct flavors to meet different security and deployment requirements:

    1. boxlang - Full Development Runtime

    • Includes NoOp (No Operation) compiler for pre-compiled class execution

    • Includes ASM compiler for runtime compilation and hot-reloading

    • Perfect for development, testing, and dynamic environments

    • Enables live code changes and interactive development

    2. boxlang-noop - Secure Production Runtime

    • NoOp compiler only - no runtime compilation capabilities

    • 100% pre-compiled code execution - zero dynamic compilation

    • Maximum security - eliminates runtime code injection vectors

    • Compliance-ready for regulated industries (finance, healthcare, government)

    Enterprise Security Win: Deploy with boxlang-noop in production to guarantee no runtime code compilation, meeting strict security policies for PCI-DSS, HIPAA, SOC 2, and government compliance requirements.

    🔌 Plug-and-Play Compiler Modules

    Compilers are now modular add-ons that can be loaded dynamically via classpath. BoxLang includes two compiler modules:

    1. bx-compiler-asm - ASM Bytecode Compiler (Recommended)

    • Direct bytecode generation using ASM library

    • Superior performance - skips Java source generation step

    • Modern JVM feature support (virtual threads, pattern matching, etc.)

    • Optimized bytecode output

    2. bx-compiler-java - Java Source Compiler

    • Generates Java source code, then compiles to bytecode

    • Legacy compatibility for debugging and inspection

    • Useful for understanding compilation process

    • Primarily for backward compatibility

    🚀 Revolutionary IBoxpiler Interface

    The new IBoxpiler interface enables true plug-and-play compiler development:

    What This Means:

    • 🔧 Custom Compilers - Build specialized compilers for your needs

    • 🎯 Domain-Specific Optimization - Create industry-specific compilation strategies

    • 🔒 Security Compilers - Implement compliance-specific compilation rules

    • ⚡ Performance Compilers - Optimize for specific deployment targets

    Example Use Cases:

    💼 Enterprise Benefits

    Security & Compliance:

    • ✅ Deploy boxlang-noop for zero-runtime-compilation security posture

    • ✅ Meet PCI-DSS, HIPAA, SOC 2 requirements with immutable runtimes

    • ✅ Pass security audits with no dynamic code execution capabilities

    Performance & Efficiency:

    • ⚡ 7MB runtime for lightning-fast container deployments

    • 🚀 Faster startup times in serverless and microservices

    • 💰 Lower cloud costs with smaller images and faster scaling

    • 🎯 Optimized memory usage for high-density deployments

    Flexibility & Innovation:

    • 🔌 Plug-and-play compilers via IBoxpiler interface

    • 🛠️ Custom compilation strategies for specialized requirements

    • 🌐 Future-proof architecture supporting new compilation targets

    Deployment Scenarios:

    Scenario
    Recommended Runtime
    Compiler

    Migration Path: Existing applications continue to work seamlessly. Simply choose boxlang for standard deployments or upgrade to boxlang-noop when security requirements demand pre-compiled-only execution.

    🎓 Technical Details

    The modular compiler architecture leverages:

    • Service Provider Interface (SPI) for compiler discovery

    • Classpath-based loading for dynamic compiler registration

    • Graceful fallback to NoOp if no compilers available

    • Zero-overhead abstraction - no performance penalty

    This architectural revolution positions BoxLang as the most flexible, secure, and enterprise-ready dynamic JVM language, with unparalleled deployment options for modern cloud-native applications.


    🌐 Revolutionary HTTP Client & Component

    The HTTP subsystem has been completely rewritten to provide modern, fluent HTTP capabilities with streaming support, connection management, and advanced features for building robust web applications.

    New http() BIF - Fluent HTTP Client

    A new http() BIF provides a fluent, chainable interface for building and executing HTTP requests with comprehensive configuration options:

    Key Features:

    • Fluent API: Chainable methods for readable request building

    • Simple Execution: send() method executes request and returns result struct directly

    • Response Transformation: transform() method applies custom transformations to results before returning

    Completely Rewritten bx:http Component

    The bx:http component has been completely rewritten to match the fluent BIF capabilities while maintaining CFML compatibility:

    New Features:

    • Streaming Callbacks: onChunk, onMessage, onError, onComplete, onRequestStart

    • SSE Support: Native Server-Sent Events handling with sse attribute

    HTTP Service - Connection Lifecycle Management

    A new HttpService manages HTTP client instances, connection pooling, and lifecycle:

    Features:

    • Automatic connection pooling and reuse

    • Connection lifecycle management

    • Statistics tracking (requests, failures, bytes transferred)

    • Graceful shutdown with connection draining

    🧼 SOAP/WSDL Client Integration

    BoxLang now includes comprehensive SOAP web service support with automatic WSDL parsing and fluent method invocation:

    New soap() BIF

    A new soap() BIF provides easy SOAP client creation:

    Features:

    • Automatic WSDL Parsing: Discovers methods, parameters, and types

    • SOAP 1.1 & 1.2 Support: Auto-detects version from WSDL

    • Fluent Method Calls: Invoke methods directly on client object

    • Response Unwrapping: Automatically unwraps single-property response structures

    Implementation Details:

    • Parses WSDL using DOM XML parser

    • Extracts operations, bindings, and port types

    • Handles XSD schema for parameter discovery

    • Builds SOAP envelopes dynamically

    🎯 Context Shutdown Listeners

    New lifecycle hooks for graceful application shutdown:

    Use Cases:

    • Database connection cleanup

    • Cache flushing

    • File handle closing

    • External service disconnection

    📚 Enhanced Metadata & Reflection

    Class metadata now includes simpleName for easier reflection:

    🤖 Core Runtime Updates

    Configuration Improvements

    Compiler Configuration: The experimental compiler setting has been refactored to a top-level directive in boxlang.json:

    JDBC URL Enhancements:

    • More robust placeholder replacements

    • Case-insensitive placeholder matching

    • Support for complex JDBC URL patterns

    Dynamic Class Loading

    The DynamicClassLoader has been enhanced with addPaths() method for dynamically loading JAR files anywhere in your BoxLang source:

    Performance Optimizations

    • Metadata Creation: Micro-optimizations using imperative programming for faster class metadata generation

    • Application Timeout Checks: Now use background thread to reduce main thread overhead

    • Thread Joining: Faster bx:thread join operations

    Query Improvements

    • Text Type Support: Query columns now support text type (maps to VARCHAR)

    • BLOB/CLOB Handling: Proper support for binary large objects

    • Column Type Tracking: Original JDBC column types preserved in query metadata

    📡 MiniServer Runtime Updates

    JSON Configuration Support

    The BoxLang MiniServer now supports loading configuration from a JSON file, allowing you to store all server settings in one place instead of passing them as command-line arguments:

    Automatic Loading:

    Explicit Path:

    Override with CLI:

    Example Configuration Files:

    Supported Configuration Options:

    Option
    Type
    Default
    Description

    Configuration Priority:

    Configuration values are loaded in the following order (later sources override earlier ones):

    1. Default values - Built-in defaults

    2. Environment variables - BOXLANG_* environment variables

    3. JSON configuration - Values from the JSON file

    4. Command-line arguments - Explicit CLI flags

    For example, if you have:

    • Environment variable: BOXLANG_PORT=3000

    • JSON file: "port": 8080

    • CLI argument: --port 9090

    The server will start on port 9090 (CLI overrides all).

    Environment File Loading:

    The envFile option allows you to specify a custom environment file to load:

    or

    • If envFile is not specified, the server looks for .env in the webroot directory (default behavior)

    • If envFile is specified, it loads that file instead

    • The path can be relative (resolved from current directory) or absolute

    Other Improvements

    • Fixed rewrite handling: No longer unnecessarily rewrites file extensions

    • Request body improvements: Better handling of empty request bodies

    • Error messages: Enhanced error reporting for malformed requests

    🤖 Servlet Runtime Updates

    • Real page context: Servlet runtime now uses proper page context (fixes many edge cases)

    • Relative path resolution: Fixed mapping path resolution issues

    • BOXLANG_DEBUG environment variable: Now properly supported

    🚀 AWS Lambda Runtime Updates

    • AWS Lambda Java Core upgraded from 1.3.0 to 1.4.0

    🛠️ Developer Experience

    JavaParser Dependencies

    Removed all JavaParser dependencies externally unless explicitly checked. This reduces runtime footprint and startup time for applications that don't use Java source parsing features.

    Feature Audit Tool

    • Enhanced to find REST classes and REST API usage

    • Better reporting of missing modules for migrations

    • Improved analysis of BoxLang feature usage

    Web Support Documentation

    All web-related BIFs and components now include proper descriptions via @BoxBIF and @BoxComponent annotations for better IDE integration and documentation generation.

    🐛 Notable Bug Fixes

    Date & Time (30+ fixes)

    • Timezone Handling: this.timezone now properly respected in Application.bx

    • Date Parsing: Fixed parsing issues with various date masks:

      • "Nov-05-2025 8:43am"

    Query Operations (15+ fixes)

    • queryFilter(): Fixed returning unexpected rows

    • querySlice(): Fixed offset handling

    • structFindKey(): Now returns proper references (not copies)

    List Operations (5+ fixes)

    • listDeleteAt(): Fixed incorrect behavior in both modes

    • List Find BIFs: Fixed unexpected matches in search operations

    • Null Appending: Fixed failures when appending null to list

    Number Formatting (5+ fixes)

    • numberFormat():

      • Fixed compatibility with "_.00" mask

      • No longer omits leading zero with _.00 mask

    HTTP & Network (10+ fixes)

    • HTTP Component:

      • Fixed basic auth regression (no longer sending proper header)

      • Fixed failures with duplicate response headers

      • Now properly handles responses with both file

    File Operations (5+ fixes)

    • fileCopy(): Now respects overwrite parameter

    • File Upload:

      • Files smaller than 10KB now properly stored on disk

      • Fixed allowed extension check when periods are present in filename

    Parser Improvements (10+ fixes)

    • Semicolons: After empty statement blocks now properly end statements

    • Whitespace: Allowed in tag closing (/ >)

    • CF Template CFCs: Fixed parsing of template-style component definitions

    • Ternary Operator

    CFML Compatibility (15+ fixes)

    • CGI Values: For compatibility, CGI values are now java.lang.String

    • Boolean Comparison: Don't compare numbers to booleans

    • isValid(): Fixed null reference errors

    Java Interop (5+ fixes)

    • Field Access: Fixed issues accessing public parent package/private class fields

    • Field Setting: Values now properly coerced when setting Java fields

    • putAll(): Fixed ClassCastException when using Map argument

    • Unmodifiable Arrays

    XML Operations (3+ fixes)

    • xmlSearch(): Returns correct value for xpath expressions

    • CFDUMP: Fixed breaking when column names contain commas

    Async Operations (2+ fixes)

    • asyncRun(): Executor argument now properly detects BoxExecutors

    • Session Scope: Fixed distributed cache persistence when request ends

    Application Lifecycle (3+ fixes)

    • Application Shutdown: Can no longer shutdown mid-request

    • Server Start: Added onServerStart support to compat mode

    • Runtime Wait: Mechanism for runtimes to wait until BoxRuntime instance fully started

    Exception Handling (3+ fixes)

    • Custom Tags in Catch: Can now call custom tags from catch blocks

    • Captured Variables: Now available when capture is performed in catch block

    • Variable Declaration: Can now declare variables using BoxExpressionInvocation

    Stored Procedures (2+ fixes)

    • Null Attribute: Component now respects "null" attribute

    • Multiple Result Sets: Fixed CFStoredProc returning multiple result sets

    Miscellaneous Fixes

    • Bytecode Versioning: Clear BL home classes folder on upgrade

    • Compiler References: Refactored 3 dangling core references to Java Boxpiler

    • variableName Type: Now allows periods in validation

    🔧 Configuration Updates

    Compiler Configuration

    The experimental compiler setting is now a top-level directive:

    Valid values: "asm" (default), "java", "noop"

    JDBC Configuration

    Enhanced placeholder support in datasource URLs:

    ⚡ Migration Notes

    Breaking Changes

    None - This release maintains full backward compatibility with 1.7.x

    Compatibility Improvements

    This release includes extensive CFML compatibility improvements:

    Date/Time Handling:

    • Better date parsing with various masks

    • Proper timezone respect in Application settings

    • Null date handling in formatting functions

    Query Operations:

    • Connection pooling with credential overrides

    • Better query metadata tracking

    • Oracle-specific improvements

    List Operations:

    • Fixed listDeleteAt() behavior

    • Better null handling

    Number Formatting:

    • numberFormat() mask compatibility

    • isNumeric() behavior matches ACF/Lucee

    HTTP Operations:

    • Basic auth header handling

    • Duplicate header support

    • Cookie expiration handling

    CGI Scope:

    • Values are now java.lang.String for compatibility

    Comparison Operations:

    • No longer compare numbers to booleans

    • Proper array vs string comparison errors

    Recommended Actions

    HTTP Migration: If you're using the old HTTP component or custom HTTP code, consider migrating to the new fluent APIs:

    SOAP Integration: If you're integrating with SOAP web services, use the new soap() BIF or traditional createObject("webservice") for automatic WSDL parsing and fluent method invocation:

    Configuration: Update your boxlang.json to use the new top-level compiler directive if you were using the experimental setting.


    🎶 Release Notes

    Bugs

    this.timezone not respected in Application.bx

    jsessionid cookie value set to null - breaks AWS WAF

    Compat: GetTempDirectory Does not Contain Trailing Slash

    ByteCode Versioning on Upgrade - clear BL home classes folder

    DateAdd changes date when added 0 'w'

    parseDateTime - Can't cast [Nov-05-2025 8:43am] to a DateTime.

    HTTP request fails with exception when server response with duplicate headers

    stored proc component not respecting "null" attribute

    cfdump breaks when column names have comma

    servlet runtime is not using the real page context

    QueryFilter returning unexpected rows

    sorting an array of numerics errors on decimals

    querysclice mishandles offset

    calling custom tag from catch block errors

    Parser: semicolons after empty statement block don't end the statement

    xmlSearch doesn't return correct value for xpath expression

    Datasources need to lead first, then caches to avoid chicken and egg issues

    When using SQLite with BoxLang, database errors (like creating a table that already exists) are not handled properly.

    StructFindKey doesn't seem to return references

    Application can shutdown mid request

    captured variable not available when capture is performed in catch block

    Boxlang server does not start if one datasource has connection issues

    reMatchNoCase result is an array with 2 elements

    Can't compare [String] against [Array]

    Date Casting issues when JVM locale is `de_DE` or `en_DE`

    Can't cast [0] to a DateTime

    FileUpload fails allowed extension check when periods are present

    list / array find BIFs returning unexpected matches

    acf/lucee compat -- numberFormat( "", '_.00' ) throws

    acf/lucee compat - numberFormat(0, "_.00") returns ".00"

    Can't cast [Jul 17, 2017 9:29:40 PM] to a DateTime.

    number format omits leading zero with _.00 mask

    isDate(0) returns true

    isValid - Cannot invoke "java.lang.CharSequence.length()" because "this.text" is null

    isDate - can't cast '0000009' to a BigDecimal

    SessionScope in distributed cache not persisting when request ends

    Dynamic Interop getField() issue when trying to access a public class parent package/private class fields

    bad parse (?) on static function invocation

    can't use `continue` inside `switch` inside `for`

    For CFML compatibility CGI values should be java,lang.string

    Nested queries ignore JSONSerialize query options

    Don't compare numbers to booleans

    lsIsCurrency - can't cast java.lang.Integer to java.lang.String

    `timeFormat` can produce strings containing non-ascii whitespace

    CF compat: allow whitespace in / > tag closing

    Parsing CF template CFC

    assingment inside ternary parses wrong

    val() sometimes returns scientific notation

    array append throws java.lang.UnsupportedOperationException when array originates from struct.keyArray()

    values not coerced when setting Java fields

    {}.putAll(Map) throws ClassCastException

    Can't cast [Jun-30-2010 04:33] to a DateTime

    Optimize DateTimeFormatter Usage

    Cannot map/filter an unmodifiable array

    query with user/pass override doesn't use connection pooling

    query with user/pass override doesn't override on-the-fly struct

    asyncRun() executor argument was not detecting BoxExecutors directly.

    Regression: isDefined returning false on struct key

    CF transpiler doesn't catch variables inside isDefined args

    CFCookie Expires crashes if using CreateTimeSpan

    Object Component - Type Default Not Being Set

    Can't cast [Jun-3-2010 04:33] to a DateTime.

    Can't cast [11/21/2025 1:05] to a DateTime

    isNumeric("true") is true on boxlang, false on lucee/acf

    Refactor 3 dangling core references to the Java Boxpiler

    CFTag support for thisTag scope behaves differently than ACF/Lucee

    You cannot declare a variable using BoxExpressionInvocation

    Compat: `format` member function undocumented but supported for DateTime objects

    Compat: `component` attribute not handled correctly by Object component

    Incorrect line number reported in tag context

    header component should add header, not replace

    Regression: HTTP Component Basic Auth no longer sending proper header

    Compat: Add handling for null dates in formatting methods

    New Features

    context shutdown listeners

    Add mechanism for runtimes to wait until BoxRuntime instance is started

    Add onServerStart support to compat module

    ServerSideEventConsumer(), SSEConsume() bif to allow from the core to connect and consume events. This is imperative for LLM integrations

    ServerSideEventConsumer to allow for any BoxLang app to consume SSE events in a streaming fashion, especially tuned for LLMs

    Fluent HTTP Client with http() bif

    HTTP Service for managing and controlling http client life-cycles

    Ability for our HTTP calls to persist connection and state across executions

    HTTP Streaming capabilities for the http components (SSE, Regular Streams)

    SOAP Client Consumer

    added simpleName to metadata for classes for ease of use

    StructFindValue breaks if any key is an array

    Improvements

    Create a way to load jars dynamically - enhanced DynamicClassLoader with addPaths()

    Remove all JavaParser dependencies externally unless you check if it exists

    Refactor the experimental compiler setting to a top-level directive in the boxlang.json: compiler

    More robust placeholder replacements in JDBC URLs

    Rename SSE BIF to ServerSideEvent and add Alias to SSE

    Added descriptions to web support bifs/components

    Add support for query type of text, map to varchar

    Enhance feature audit to find REST classes

    Support rowID/generatedKey for Oracle

    Make datasource URL placeholder replacements case-insensitive

    Faster bx:thread joining

    Allow JDBC Drivers to override query column types

    variableName type allows periods

    Preserve whitespace in error messages in default web Error page

    track original JDBC col type and make available in query meta

    varchar param doesn't match char field in Oracle driver

    Support BLOB and CLOB properly

    Compat-- upper case outer struct keys when serializing query

    Use background thread to check app timeouts

    Micro optimizations to promote speed when creating metadata by using imperative programming

    println() better handling of java native arrays

    Oracle stored procs support for ref cursors

    rereplace() ignore invalid backreference groups

    Default choice for most applications

    Reduced attack surface - no compiler means no compilation exploits

  • Immutable deployments - code cannot be modified at runtime

  • Perfect for production environments requiring security certifications

  • Default compiler for production applications

    🌐 Alternative Targets - Compile BoxLang to JavaScript, WASM, native code, etc.

  • 🔬 Research & Innovation - Experiment with new compilation techniques

  • ✅ Eliminate entire classes of code injection vulnerabilities
    🔬
    Research-friendly
    for academic and innovation projects

    Production (High Security)

    boxlang-noop

    None (pre-compiled only)

    Regulated Industries

    boxlang-noop

    None (pre-compiled only)

    Government/Military

    boxlang-noop

    None (pre-compiled only)

    Containerized Apps

    boxlang-noop

    None (smaller images)

    Thread-safe compilation for concurrent applications

    HTTP/2 Support: Modern HTTP/2 by default with HTTP/1.1 fallback

  • Streaming: Chunk-based streaming for large responses and SSE

  • Connection Pooling: Automatic connection reuse and management

  • Client Certificates: SSL/TLS client certificate authentication

  • Proxy Support: HTTP/HTTPS proxy with authentication

  • Callbacks: Rich callback system (onChunk, onError, onComplete, onRequestStart)

  • Error Handling: throwOnError option automatically throws exceptions for HTTP errors (4xx/5xx)

  • HTTP/2: Full HTTP/2 support with httpVersion attribute

  • Connection Management: Persistent connections and connection pooling

  • Client Certificates: SSL/TLS client certificate authentication

  • Better Error Handling: throwOnError attribute for automatic exception throwing

  • Document/Literal Wrapped: Full support for document/literal wrapped style

  • Parameter Handling: Automatic parameter type conversion and validation

  • Automatic BoxLang Type Mapping: Maps SOAP types to BoxLang types automatically

  • Supports complex types and nested structures
  • Compatible with invoke() BIF and bx:invoke component

  • Logging final state
    Oracle Improvements
    :
    • VARCHAR params now match CHAR fields correctly

    • Support for generated keys (ROWID)

    • Stored procedure ref cursor support

    debug

    boolean

    false

    Enable debug mode

    configPath

    string

    null

    Path to BoxLang configuration file

    serverHome

    string

    null

    BoxLang server home directory

    rewrites

    boolean

    false

    Enable URL rewrites

    rewriteFileName

    string

    "index.bxm"

    Rewrite target file

    healthCheck

    boolean

    false

    Enable health check endpoints

    healthCheckSecure

    boolean

    false

    Restrict detailed health info to localhost only

    envFile

    string

    null

    Path to custom environment file (relative or absolute)

    Environment variables are loaded as system properties and can be used throughout the application

    Session management: Fixed jsessionid cookie handling (prevents AWS WAF issues)
  • Concurrent request handling: Better handling of in-progress onApplicationStart()

  • "Jun-30-2010 04:33"

  • "Jun-3-2010 04:33"

  • "11/21/2025 1:05"

  • "Jul 17, 2017 9:29:40 PM"

  • dateAdd(): No longer mutates date when adding 0 weeks

  • isDate(): Fixed various edge cases:

    • isDate(0) now returns false

    • Handles scientific notation strings

    • Better handling of invalid numeric strings

  • Date Casting: Fixed issues with JVM locales de_DE and en_DE

  • dateConvert(): Resolved conversion errors

  • timeFormat(): Fixed non-ASCII whitespace in output

  • Null Dates: Added handling for null dates in formatting methods

  • DateTime Optimization: DateTimeFormatter usage optimized for better performance

  • .format() Member: Undocumented but now properly supported on DateTime objects

  • structFindValue(): Fixed crashes when keys contain arrays

  • Nested Queries: Now respect JSONSerialize query options

  • Connection Pooling:

    • Fixed queries with user/pass override not using pooling

    • Properly override credentials with on-the-fly struct syntax

  • SQLite Error Handling: Database errors now properly handled

  • Empty string with _.00 mask no longer throws

  • Returns proper value for zero with _.00 mask

  • isNumeric(): isNumeric("true") now returns false (matches ACF/Lucee)

  • val(): Fixed occasional scientific notation in results

  • lsIsCurrency(): Fixed type casting issues

  • and
    path
    attributes
  • Cookie Component:

    • Fixed expires attribute crashes with createTimeSpan

    • Better date handling for cookie expiration

  • Header Component: Now adds headers instead of replacing (correct CFML behavior)

  • Compression: Fixed gzip decompression issues

  • Fixed regression where content wasn't committed to disk

  • Empty allow argument now treated correctly

  • getFileInfo(): Returns correct type string for directories

  • expandPath(): Fixed using wrong base path when Application.bx in different directory

  • getTempDirectory(): Now contains trailing slash (CFML compat)

  • : Assignment inside ternary now parses correctly
  • continue in switch: Can now use continue inside switch inside for loop

  • Static Function Invocation: Fixed parse error on static method calls

  • CF Transpiler:

    • Now catches variables inside isDefined() args

    • Better handling of CF template CFC structures

  • isDefined()
    : Fixed regression returning false on struct keys
  • reMatchNoCase(): Result is now proper array (not array with 2 elements)

  • Array Comparison: Fixed "Can't compare [String] against [Array]" error

  • structSort(): Fixed issues with unmodifiable arrays from keyArray()

  • Object Component:

    • Type default now being set correctly

    • component attribute handled correctly

  • Custom Tags: thisTag scope now behaves like ACF/Lucee

  • Line Numbers: Correct line numbers reported in tag context

  • : Can now map/filter unmodifiable arrays
  • Native Array Printing: println() better handles Java native arrays

  • Datasource Loading
    : Datasources load first, then caches (avoids chicken/egg issues)
  • Datasource Errors: Server now starts even if one datasource has connection issues

  • Error Messages
    : Preserve whitespace in default web error page
  • Query Column Keys: Upper case outer struct keys when serializing query (compat)

  • rereplace(): Ignore invalid backreference groups (don't throw)

  • Development

    boxlang

    ASM (hot-reload enabled)

    CI/CD Testing

    boxlang

    ASM

    Staging

    boxlang or boxlang-noop

    ASM

    Production (Standard)

    boxlang

    port

    number

    8080

    The port to listen on

    host

    string

    "0.0.0.0"

    The host to bind to

    webRoot

    string

    current directory

    BL-1850
    BL-1874
    BL-1884
    BL-1886
    BL-1888
    BL-1889
    BL-1890
    BL-1892
    BL-1896
    BL-1897
    BL-1899
    BL-1900
    BL-1901
    BL-1906
    BL-1908
    BL-1909
    BL-1910
    BL-1911
    BL-1912
    BL-1913
    BL-1914
    BL-1926
    BL-1927
    BL-1928
    BL-1929
    BL-1930
    BL-1931
    BL-1932
    BL-1933
    BL-1934
    BL-1935
    BL-1938
    BL-1939
    BL-1941
    BL-1942
    BL-1943
    BL-1946
    BL-1947
    BL-1948
    BL-1949
    BL-1950
    BL-1951
    BL-1952
    BL-1956
    BL-1958
    BL-1959
    BL-1960
    BL-1962
    BL-1963
    BL-1965
    BL-1966
    BL-1967
    BL-1969
    BL-1971
    BL-1972
    BL-1973
    BL-1976
    BL-1977
    BL-1978
    BL-1980
    BL-1981
    BL-1982
    BL-1983
    BL-1984
    BL-1985
    BL-1987
    BL-1988
    BL-1989
    BL-1994
    BL-1995
    BL-1996
    BL-1997
    BL-1998
    BL-1835
    BL-1891
    BL-1893
    BL-1895
    BL-1898
    BL-1921
    BL-1922
    BL-1923
    BL-1924
    BL-1970
    BL-1974
    BL-1990
    BL-1315
    BL-1518
    BL-1617
    BL-1868
    BL-1887
    BL-1894
    BL-1902
    BL-1903
    BL-1905
    BL-1918
    BL-1919
    BL-1920
    BL-1925
    BL-1936
    BL-1937
    BL-1940
    BL-1945
    BL-1957
    BL-1968
    BL-1975
    BL-1986
    BL-1991
    BL-1992

    ASM

    Path to the webroot directory

    # Development/Standard deployment
    java -jar boxlang-1.8.0.jar myapp.bx
    
    # Secure production deployment (pre-compiled only)
    java -jar boxlang-noop-1.8.0.jar myapp.bx
    // boxlang.json - Choose your compiler
    {
      "compiler": "asm",  // Use ASM compiler (default)
      // OR
      "compiler": "java"  // Use Java source compiler
    }
    public interface IBoxpiler {
        // Compile BoxLang source to bytecode
        byte[] compile( SourceCode source );
    
        // Get compiler metadata
        String getName();
        String getVersion();
    }
    // Financial services: Compiler with embedded audit logging
    compiler = new AuditCompiler()
        .enableTracing()
        .logToCompliance( "audit.log" );
    
    // IoT: Compiler optimized for embedded devices
    compiler = new EmbeddedCompiler()
        .optimizeForMemory()
        .targetArch( "ARM64" );
    
    // Blockchain: Compiler with cryptographic verification
    compiler = new VerifiableCompiler()
        .signOutput()
        .enableProofOfCompilation();
    // Simple GET request with fluent API
    result = http( "https://api.example.com/data" ).send();
    println( "Status: #result.statusCode#" );
    println( "Body: #result.fileContent#" );
    
    // Or send async and receive a box future
    boxFuture = http( "https://api.example.com/data" )
        .get()
        .sendAsync()
    
    // POST with JSON body
    result = http( "https://api.example.com/users" )
        .post()
        .header( "Content-Type", "application/json" )
        .body( { name: "John Doe", email: "[email protected]" } )
        .send();
    println( "User created: #result.fileContent#" );
    
    // File upload with multipart
    http( "https://api.example.com/upload" )
        .post()
        .multipart()
        .file( "document", "/path/to/file.pdf" )
        .formField( "description", "Important document" )
        .send();
    
    // Stream large response with chunking
    http( "https://api.example.com/large-data" )
        .get()
        .onChunk( ( chunk ) => {
            // Process each chunk as it arrives
            println( "Received chunk: #chunk.data.len()# bytes" );
        } )
        .send();
    
    // Consume Server-Sent Events (SSE)
    http( "https://api.example.com/events" )
        .get()
        .header( "Accept", "text/event-stream" )
        .onChunk( ( event ) => {
            // Process SSE events in real-time
            println( "Event: #event.event#" );
            println( "Data: #event.data#" );
        } )
        .send();
    
    // Configure connection settings
    result = http( "https://api.example.com/data" )
        .connectionTimeout( 30 )
        .httpVersion( "HTTP/2" )
        .redirect( true )
        .proxyServer( "proxy.company.com", 8080 )
        .clientCert( "/path/to/cert.p12", "password" )
        .get()
        .send();
    
    // Transform response with custom function
    users = http( "https://api.example.com/users" )
        .get()
        .transform( ( result ) => deserializeJSON( result.fileContent ) )
        .send(); // Returns deserialized array instead of result struct
    // Simple GET request
    <bx:http url="https://api.example.com/data" result="apiResult" />
    <bx:dump var="#apiResult.statusCode#" />
    
    // POST with JSON
    <bx:http
        method="POST"
        url="https://api.example.com/users"
        result="response"
        throwOnError="true">
        <bx:httpparam type="header" name="Content-Type" value="application/json" />
        <bx:httpparam type="body" value='{"name":"John","email":"[email protected]"}' />
    </bx:http>
    
    // File upload (multipart)
    <bx:http
        method="POST"
        url="https://api.example.com/upload"
        multipart="true">
        <bx:httpparam type="file" name="document" file="/path/to/file.pdf" />
        <bx:httpparam type="formfield" name="description" value="Important document" />
    </bx:http>
    
    // Download file
    <bx:http
        url="https://example.com/downloads/report.pdf"
        file="report.pdf"
        path="/downloads/"
        getAsBinary="yes" />
    
    // Streaming with callbacks
    <bx:http
        url="https://api.example.com/stream"
        onChunk="#( chunk ) => processChunk( chunk )#"
        onError="#( error ) => logError( error )#"
        onComplete="#() => println( 'Stream complete' )#" />
    
    // Server-Sent Events (SSE)
    <bx:http
        url="https://api.example.com/events"
        sse="true"
        onMessage="#( event ) => handleSSEEvent( event )#" />
    
    // Client certificate authentication
    <bx:http
        url="https://secure-api.com/data"
        clientCert="/path/to/cert.p12"
        clientCertPassword="secret" />
    
    // Proxy configuration
    <bx:http
        url="https://external-api.com"
        proxyServer="proxy.company.com"
        proxyPort="8080"
        proxyUser="username"
        proxyPassword="password" />
    // Clients are automatically managed and reused based on configuration
    client1 = http( "https://api.example.com" );
    client2 = http( "https://api.example.com" ); // Reuses same connection pool
    
    // Access HTTP statistics
    stats = getBoxRuntime().getHttpService().getStats();
    println( "Total requests: #stats.totalRequests#" );
    println( "Active connections: #stats.activeConnections#" );
    // Create SOAP client from WSDL using soap() BIF
    ws = soap( "http://example.com/service.wsdl" );
    
    // Configure client settings
    ws = soap( "http://example.com/service.wsdl" )
        .timeout( 60 )
        .withBasicAuth( "username", "password" )
        .header( "X-Custom-Header", "value" );
    
    // Invoke methods directly (discovered from WSDL)
    result = ws.getUserInfo( userID: 123 );
    println( "User: #result.name#" );
    
    // Alternative: createObject() syntax (traditional)
    ws = createObject( "webservice", "http://example.com/service.wsdl" );
    result = ws.getUserInfo( userID: 123 );
    
    // Use invoke() function for dynamic calls
    result = invoke( ws, "getUserInfo", { userID: 123 } );
    
    // Use in components
    <bx:invoke
        webservice="http://example.com/service.wsdl"
        method="getUserInfo"
        userID="123"
        returnVariable="userInfo" />
    
    // Inspect available operations
    operations = ws.getOperationNames();
    println( "Available operations: #operations.toList()#" );
    
    // Get operation details
    opInfo = ws.getOperationInfo( "getUserInfo" );
    println( "Parameters: #opInfo.parameters.toList()#" );
    // In Application.bx
    component {
        this.name = "MyApp";
    
        function onApplicationStart() {
            // Register shutdown listener
            application.resources = setupResources();
    
            getBoxContext().registerShutdownListener( () => {
                // Clean up resources on shutdown
                application.resources.close();
                println( "Application shutdown complete" );
            } );
        }
    }
    meta = getMetadata( myObject );
    println( "Class: #meta.fullName#" );
    println( "Simple name: #meta.simpleName#" ); // New in 1.8.0
    {
      "compiler": "asm",  // or "java" or "noop"
      "runtime": {
        // other runtime settings
      }
    }
    // Load external JARs at runtime
    getRequestClassLoader().addPaths( [ "/path/to/library.jar", "/path/to/another.jar" ] );
    
    // Now load classes from those JARs
    MyClass = createObject( "java", "com.example.MyClass", getRequestClassLoader() );
    # Looks for miniserver.json in current directory
    boxlang-miniserver
    boxlang-miniserver /path/to/config.json
    # CLI arguments override JSON configuration
    boxlang-miniserver miniserver.json --port 9090 --debug
    // Basic configuration
    {
      "port": 8080,
      "webRoot": "./www"
    }
    
    // Development configuration
    {
      "port": 8080,
      "host": "127.0.0.1",
      "webRoot": "./src/webapp",
      "debug": true,
      "rewrites": true,
      "rewriteFileName": "index.bxm"
    }
    
    // Production configuration
    {
      "port": 80,
      "host": "0.0.0.0",
      "webRoot": "/var/www/myapp",
      "debug": false,
      "rewrites": true,
      "rewriteFileName": "index.bxm",
      "healthCheck": true,
      "healthCheckSecure": true,
      "serverHome": "/opt/boxlang",
      "envFile": "/etc/boxlang/.env.production"
    }
    {
      "envFile": ".env.local"
    }
    {
      "envFile": "/etc/myapp/.env.production"
    }
    {
      "compiler": "asm",
      "runtime": {
        // runtime settings
      }
    }
    {
      "datasources": {
        "myDB": {
          "driver": "mysql",
          "url": "jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}",
          "username": "${DB_USER}",
          "password": "${DB_PASS}"
        }
      }
    }
    // Old style (component)
    <bx:http url="https://api.example.com" method="GET" result="myResult" />
    
    // New style (fluent BIF)
    myResult = http( "https://api.example.com" )
        .get()
        .send(); // Returns the result struct directly
    
    // Or with transformation
    data = http( "https://api.example.com/users.json" )
        .get()
        .transform( ( result ) => deserializeJSON( result.fileContent ) )
        .send(); // Returns deserialized data
    // New soap() BIF (recommended)
    ws = soap( "http://example.com/service.wsdl" )
        .timeout( 60 )
        .withBasicAuth( "user", "pass" );
    
    // Or traditional createObject
    ws = createObject( "webservice", "http://example.com/service.wsdl" );
    
    // Invoke methods
    result = ws.methodName( arg1, arg2 );

    1.6.0

    October 3, 2025

    BoxLang 1.6.0 brings significant performance improvements, enhanced async capabilities with advanced executor monitoring, improved REPL/MiniConsole framework, and better module mapping support. This release focuses on optimization, developer experience, and compatibility enhancements.

    🚀 Major Highlights

    📚 BoxLang Documentation MCP Server

    BoxLang documentation is now accessible via the Model Context Protocol (MCP)! Connect AI assistants like Claude, GitHub Copilot, and other MCP-compatible tools directly to the comprehensive BoxLang documentation for instant access to language references, framework features, and best practices.

    Connect to the MCP Server:

    • Direct MCP URL: https://boxlang.ortusbooks.com/~gitbook/mcp

    • One-Click VSCode Installation:

    This enables developers to:

    • 🔍 Search BoxLang documentation semantically from within AI assistants

    • 💡 Get instant answers about BIFs, components, and framework features

    • 📖 Access code examples and best practices without leaving your workflow

    • 🤖 Enhance AI-assisted BoxLang development with authoritative documentation

    Enhanced BoxExecutor with Health Monitoring & Statistics

    The ExecutorRecord has been transformed into a full-fledged BoxExecutor class with comprehensive health monitoring, activity tracking, and advanced statistics. This provides deep insights into your async operations.

    You can now retrieve detailed stats and health information about your executors. The following are the different status strings you can expect:

    • healthy - Executor is operating normally within defined thresholds.

    • degraded - Executor is experiencing some issues but is still functional. May indicate high load or minor problems.

    • critical - Executor is in a critical state and may not be functioning properly. Immediate attention is required.

    The new Executor Health Report provides a detailed analysis of the executor's health, including detected issues, recommendations for improvement, alerts for critical conditions, and insights into performance trends. The result is a structure containing the following keys:

    • status - Overall health status of the executor.

    • summary - A brief summary of the executor's health.

    • issues - An array of detected issues affecting the executor's health.

    This opens the door for our future tooling around executor management and monitoring.

    MiniConsole Framework & REPL Improvements

    A new MiniConsole framework has been introduced, bringing sophisticated terminal interaction capabilities and dramatically improved REPL experience with:

    • Syntax highlighting for BoxLang code with color themes (dark/light palettes)

    • Tab completion for BIFs and components with intelligent providers

    • Cross-platform key handling (Windows, macOS, Linux)

    • Multi-line editing with continuation prompts

    Module Public Mapping Support

    Modules have now a new mapping by convention called publicMapping that allows you to define a public mapping for your module's assets. This is in addition to the existing mapping property which is used for internal module paths and not visible outside the module. The publicMapping can be defined as a simple string or a struct for advanced configuration.

    🤖 Core Runtime Updates

    Performance Optimizations

    We have done a second round of performance optimizations focusing on reducing thread contention, memory usage, and improving throughput. Key improvements include:

    • Deferred interception data creation based on hasState() checks, which have increased throughput by over 50x

    • Removed synchronized modifiers on singleton getInstance() methods, improving concurrency and dramatically reducing thread contention

    • Non-concurrent maps for context config and other internal data structures (reduced thread contention dramatically)

    These performance improvements can lead to significant speedups in high-concurrency environments and reduce memory footprint considerably. Compilation and execution times are becoming instant in some scenarios. This is a significant jump in performance for BoxLang. We have updated our TechEmpower benchmarks to include BoxLang and how it compares to Adobe and Lucee using vanilla code and also ColdBox. We will be releasing the results soon and will always be available publicly.

    We have seen performance and throughput improvements ranging from 45-65% in various benchmarks and vanilla ColdBox applications, between 1.6 and previous 1.5.x releases. Using BoxLang and our SocketBox websocket's library and server we have seen capabilities of over 5,000 concurrent websocket connections running smoothly on a modest development machine.

    Performance Stats

    • Plain text and updates tests increased from 23,000 requests per second to over 53,000 requests per second on modest cloud VM

    • SQL queries tests jumped from 15k requests per second to over 18k requests per second

    • 5,000 concurrent websocket connections on a dev laptop with 256 MB of memory allocated to the JVM (Windows, Linux would be higher)

      • CPU once they were all connected and sending 500 heartbeat req/sec was only 4-5%

    More coming soon.

    DateTime Enhancements

    • Immutability flag to prevent timezone mutation during formatting

    • Performance optimizations for DateTime class operations

    • Improved date parsing with better mask support (yyyy/M/d)

    • Two-digit year handling

    JDBC & Database

    • Disabled connection leak detection by default for better performance

    • Fixed NPE in bx-mariadb when checking DDL statement results

    • Improved query param encoding in HTTP requests

    📡 MiniServer Runtime Updates

    Enhanced Error Handling

    • Improved exception handling when invalid arguments are provided

    • STOMP heartbeat responses now properly returned from miniserver

    • Version flag support - boxlang-miniserver --version displays version information

    🤖 Servlet Runtime Updates

    Jakarta EE Compliance

    • Updated web.xml to Jakarta specs with proper namespace declarations

    • Integration tests added to verify WAR deployment can expand, deploy, and run BoxLang code successfully

    • Fixed file upload handling for small files in servlet environment

    🚀 AWS Lambda Runtime Updates

    • Upgraded AWS Lambda Java Core from 1.3.0 to 1.4.0

    🛠️ Developer Experience

    BIF & Component Documentation

    Built-in functions and components now include runtime descriptions via the description attribute in @BoxBIF and @BoxComponent annotations:

    CFTranspile Improvements

    • Verbose mode added to cftranspile command for detailed conversion insights

    • Better visibility into transpilation issues and potential data concerns

    Feature Audit Tool

    • Updated feature audit with improved output

    • Lists missing modules to help identify required BoxLang modules for migrations

    🐛 Notable Bug Fixes

    Component & Function Fixes

    • structKeyExists() now works on closures

    • imageRead() properly expands paths and handles URIs

    • bx:cookie expires attribute now processes dates before strings

    XML Handling

    • XMLElemNew() usage - XMLAttribute on produced nodes no longer throws errors

    • Empty xmlNew() results now produce valid XML objects with nodes

    • Multiple BOMs - parsing no longer fails on files with multiple byte order marks

    Parsing Improvements

    • Extra spaces in tag close now parse correctly

    • return keyword can now be used as a variable name

    • component keyword can be used as annotation name

    List & Compatibility Fixes

    • ListDeleteAt() retains leading delimiters in compatibility mode

    • CF compat nulls now equal empty strings

    • IsValid() supports number type in compatibility mode

    🔧 Configuration Updates

    Datasource Environment Variables

    • Datasource keys are now searched for environment variable replacements in configuration

    • Supports patterns like ${DB_HOST}, ${DB_PORT} in datasource definitions

    Mapping Configuration

    • Enhanced mapping registration detects between simple and complex mappings

    • Better handling of module mappings with usePrefix and external flags

    ⚡ Migration Notes

    Breaking Changes

    None registered for this release.

    Compatibility Improvements

    This release includes numerous compatibility fixes for Adobe ColdFusion and Lucee migrations:

    • DateFormat mask handling (m vs M)

    • ListDeleteAt delimiter behavior

    • Null handling in CF compat mode

    • IsValid type validation

    Performance Considerations

    • JDBC connection leak detection is now disabled by default. Enable via configuration if needed for debugging

    • Trusted cache behavior - Application descriptor lookups are now cached when trusted cache is enabled

    • Consider using the new BoxExecutor health monitoring to track async operation performance

    🎶 Release Notes

    Improvements

    Update the feature audit tool - Part 2

    Bad link on dateformat in docs

    Performance optimizations for DateTime class

    HTTP Param - Change URL param handling to Encode Always

    defer intercept data creation based on hasState()

    avoid synchronized modifier on singleton getInstance() methods

    Convert context config to non-concurrent maps for performance

    assorted small performance fixes

    Disable JDBC connection leak detection by default

    Add weak reference disk class caching

    Cache Application descriptor lookups when trusted cache is enabled

    Provide overloaded internal expandpath method for known mappings to avoid context.getConfig()

    bx:cookie did not try to process `expires` as a date before a string

    Improve exception handling on miniserver when arguments are invalid

    Added verbose mode to the cftranspile command to see issues or potential data

    calling getCachedObjectMetadata registers as a hit

    Improve type names in error messages

    modify getInstance pattern in ASM compiler to avoid method-level synchronization

    Configuration mappings registration needs to be updated to detect between a simple and a complex mapping

    Add `context` to intercept data whenever you can find interception calls that require it

    The key to the datasource needs to be searched for env replacements in the configuraiton

    Update feature audit to output list of missing modules

    return STOMP heartbeat responses from miniserver

    Bugs

    ImageRead does not expand the path

    imageRead with URIs

    When using compatibility mode and set to Lucee, handling of unquoted keys in json is not consistent with Lucee.

    duplication util doesn't use correct class loader when serializing classes

    Cannot use structKeyExists on closure

    small files not uploaded in servlet

    Compare Operations Should Not Use Collations unless Locale Sensitivity is Specified

    Change Deprecated Uses of StringUtils compare and contains functions to use new Strings API

    number caster doesn't trim spaces on incoming strings

    Native toString output of ZonedDateTime object not being parsed/cast correctly

    HTTP Component not returning result if `file` and `path` are specified

    File/Path compat differences between BL/Lucee/Adobe

    Add Immutability Flag to DateTime Objects to Prevent Timezone Mutation on Format

    Inconsistent default formats between parsed date results

    Can't create application caches on Windows

    Ensure Two-Digit Year is Always Assumptive of Current Millenium in Date Parsing

    Dates with Mask `yyyy/M/d` are not parsed natively

    cache component announcing wrong interception point

    Compat behavior - ListDeleteAt should retain leading delimiters

    CF compat nulls need to equal empty string

    Compat: IsValid does not support `number` as a type

    XMLAttribute usage on node produced by XMLElemNew Throws Error

    Empty xmlNew Result produces an XML object with no node

    ASM bug on loading a pre-compiled class when doing renaming of identifiers: illegalArgumentException null

    In function [logMessage], argument [logEvent] with a type of [boxgenerated.boxclass.coldbox.system.logging.Logevent$cfc] does not match the declared type of [coldbox.system.logging.LogEvent] when using pre-compiled source

    boxlang run compiled template gets confused when doing shebang detection

    pre-compiled classes not getting their name metadata set properly

    bx-mariadb throwing NPE checking for results on DDL statement

    Extra space in tag close not parsing

    Use of return keyword as variable

    Use of component keyword as annotation name

    FQN starting with _

    property shortcut with FQN as type

    Parsing fails on files with multiple BOMs

    Compat - For DateFormat BIF treat all `m` letters as `M`

    New Features

    Enhance executor stats

    Update servlet web.xml to new Jakarta specs and added intgration test for the WAR to check it can expand, deploy and run BoxLang code.

    ExecutorRecord becomes a class BoxExecutor due to instance data required for stats and health metrics

    Enhance BoxLang BoxExecutor with Health Monitoring, Activity Tracking, and Advanced Statistics

    Bump com.amazonaws:aws-lambda-java-core from 1.3.0 to 1.4.0

    this.mapping for modules needs to support simple string and a struct of mapping options

    Introduce this.publicMapping for modules to allow for public mapping by convention

    Repl Improvements + MiniConsole Framework

    Adding a description to the BoxBif and BoxComponent annotations for short inline descriptions

    Add a boxlang-miniserver --version to spit out the version information

    BIFS and Components now include a runtime description

    Tasks

    remove unused variables in the module record that's not implemented

    idle - Executor has no active tasks and is idle.

  • shutdown - Executor is in the process of shutting down and will not accept new tasks.

  • terminated - Executor has been terminated and is no longer operational.

  • draining - Executor is finishing existing tasks but not accepting new ones.

  • recommendations - An array of recommended actions to improve executor health.
  • alerts - An array of critical alerts that require immediate attention.

  • insights - An array of insights into executor performance and trends.

  • lastChecked - Timestamp of the last health check.

  • Command history with shortcuts (!!, !n)

  • Color printing utilities for rich terminal output

  • Much More

  • Weak reference disk class caching for better memory management, 80% reduction in memory usage in some scenarios

  • Cached Application descriptor lookups when trusted cache is enabled

  • Overloaded internal expandPath() method for known mappings to avoid context.getConfig() calls

  • ASM compiler improvements to avoid method-level synchronization in getInstance() patterns

  • This test pushed 55,000 requests to the server in ~1 minute with an average processing time of 24ms and 0 errors

  • Total heap used never went past 190 MB during the test

  • always assumes current millennium
  • Consistent default formats between parsed date results

  • DateFormat BIF compatibility - all m letters treated as M

  • HTTP component now returns results when both file and path are specified

  • File/Path compatibility improved between BoxLang, Lucee, and Adobe CF

  • FQN starting with underscore now supported
  • Property shortcuts with FQN types now work properly

  • Lucee JSON compatibility - unquoted keys in JSON handled consistently with Lucee when in compatibility mode

  • Duplication util now uses correct class loader when serializing classes

  • JSON unquoted key handling

    Install BoxLang MCP Server
    BL-1591
    BL-1735
    BL-1741
    BL-1742
    BL-1747
    BL-1748
    BL-1749
    BL-1750
    BL-1752
    BL-1753
    BL-1754
    BL-1755
    BL-1758
    BL-1765
    BL-1767
    BL-1775
    BL-1785
    BL-1786
    BL-1793
    BL-1794
    BL-1795
    BL-1802
    BL-1805
    BL-1586
    BL-1672
    BL-1690
    BL-1695
    BL-1710
    BL-1727
    BL-1729
    BL-1731
    BL-1732
    BL-1736
    BL-1737
    BL-1738
    BL-1739
    BL-1740
    BL-1743
    BL-1744
    BL-1745
    BL-1751
    BL-1756
    BL-1763
    BL-1766
    BL-1769
    BL-1771
    BL-1776
    BL-1777
    BL-1782
    BL-1784
    BL-1789
    BL-1797
    BL-1798
    BL-1799
    BL-1800
    BL-1801
    BL-1803
    BL-1804
    BL-1498
    BL-1718
    BL-1725
    BL-1726
    BL-1746
    BL-1760
    BL-1762
    BL-1764
    BL-1779
    BL-1780
    BL-1783
    BL-1759
    // Get executor and check its comprehensive stats including health
    executor = asyncService.getExecutor( "myExecutor" )
    stats = executor.getStats()
    
    // Returns detailed metrics including:
    // - Basic info: name, type, created, uptime, lastActivity
    // - Task metrics: taskSubmissionCount, taskCount, completedTaskCount, activeCount
    // - Pool metrics: poolSize, corePoolSize, maximumPoolSize, largestPoolSize
    // - Queue metrics: queueSize, queueCapacity, queueUtilization
    // - Utilization: poolUtilization, threadsUtilization, taskCompletionRate
    // - Health status: healthStatus ("healthy", "degraded", "critical", "idle", etc.)
    // - Health report: detailed analysis with issues, recommendations, alerts, insights
    
    // Check if executor is healthy (simple boolean check)
    isHealthy = executor.isHealthy()  // returns true/false
    
    // Access health information from stats
    healthStatus = stats.healthStatus  // "healthy", "degraded", "critical", "idle", "shutdown", "terminated", "draining"
    healthReport = stats.healthReport  // Detailed health analysis
    
    // Health report includes:
    // - status: overall health status
    // - summary: brief description
    // - issues: array of detected problems
    // - recommendations: array of suggested actions
    // - alerts: array of critical alerts
    // - insights: array of performance insights
    // REPL now includes smart syntax highlighting
    📦 BoxLang> arrayMap( [1,2,3], (x) => x * 2 )
    // BIFs in bright green, functions in purple
    
    // Tab completion for components and BIFs
    � BoxLang> array<TAB>
    // Shows: arrayMap, arrayFilter, arrayEach, arrayReduce...
    // In ModuleConfig.bx
    component {
        // Simple string - creates /bxModules/{moduleName}/public mapping
        this.publicMapping = "public"
    
        // Or use a struct for advanced config
        this.publicMapping = {
            name: "assets",
            path: "resources/public",
            usePrefix: true,
            external: true
        }
    
        // Enhanced this.mapping also supports structs
        this.mapping = {
            name: "myModule",
            path: "models",
            usePrefix: false
        }
    }
    @BoxBIF(
        description = "Returns the length of a string, array, struct, or query"
    )
    public class Len extends BIF {
        // ...
    }
    
    @BoxComponent(
        name = "Http",
        description = "Makes HTTP/HTTPS requests to remote servers"
    )
    public class Http extends Component {
        // ...
    }

    1.4.0

    August 2, 2025

    We're excited to announce BoxLang v1.4.0, our biggest release yet! This major update brings powerful new features, performance improvements, and extensive bug fixes that make BoxLang more robust and developer-friendly than ever.

    🚀 Core Runtime Updates

    Revolutionary Asynchronous Programming Framework

    BoxLang v1.4.0 introduces a game-changing asynchronous programming framework that sets a new standard for JVM languages. This isn't just another async implementation—it's a comprehensive, battle-tested framework that makes parallel programming accessible, intuitive, and powerful in ways that other languages and frameworks simply don't offer.

    What makes this revolutionary:

    • Zero boilerplate - Write async code as naturally as synchronous code

    • Built-in parallel primitives - No need for complex thread management or executor services

    • Functional composition - Chain, compose, and transform async operations with ease

    • Exception safety - Automatic error propagation and handling across async boundaries

    Core async primitives that change everything:

    • asyncRun() - Transform any operation into a non-blocking future (with runAsync() as an alias)

    • asyncAll() - Execute multiple operations in parallel and aggregate results—no more callback hell or complex coordination

    • asyncAllApply() - Map-reduce operations across collections in parallel with automatic work distribution

    This is async programming reimagined. While other languages force you to deal with complex promises, callbacks, or verbose async/await patterns, BoxLang gives you declarative parallel programming that just works.

    This powerful new framework is fully documented in our comprehensive , including detailed sections on , , , , and .

    Enhanced BoxLang Mappings

    Mappings now support an external flag (defaults to false) for better module organization and security. All mappings in the global runtime config boxlang.json and those in the Application.bx|cfc are external = true by default, meaning they can be accessed via the URL.

    All module mappings are external = false by default, meaning they are not accessible via the URL.

    Loop Grouping Enhancements

    BoxLang now supports complex nested grouping in queries and loops, allowing you to easily group data by multiple fields. This makes it simpler to generate reports and summaries directly in your templates.

    ⚡Miniserver Updates

    Read all about the new miniserver features in our .

    Environment Variable Support (.env)

    The BoxLang miniserver now supports .env files for configuration management. It will look for a .env file in the root of your project and load environment variables from it. This allows you to easily manage configuration settings without hardcoding them in your codebase.

    Miniserver Health Checks

    Added simple health check endpoints for container-based deployments, making BoxLang more cloud-native.

    Hidden File Protection

    Basic protection against serving hidden files (dot files) in the miniserver for improved security.

    🔧 Performance & Optimization Improvements

    String Performance Enhancements

    • Significant performance improvements for toScript() BIF

    • Optimized string operations throughout the runtime

    • Better memory management for large string operations

    Custom Component Lookup Optimization

    • Refactored custom component and class lookup for improved performance

    • Better caching mechanisms for frequently accessed components

    • Reduced overhead in component resolution

    Module Class Visibility

    • Module classes are now properly visible to the context classloader

    • Improved module loading and initialization performance

    JSON Processing Improvements

    • Removed JSON serialization limits

    • Enhanced JSON serialization of throwable objects

    • Better handling of complex object graphs in JSON serialization

    🛠️ Language & Runtime Improvements

    Enhanced Date/Time Handling

    • Support for more natural date parsing masks (case-insensitive)

    • Better timezone handling in DateTimeCaster

    • Improved CFML compatibility for partial years

    • Fixed issues with GregorianCalendar.getTime()

    Improved Type Coercion

    • Skip type coercion for === operator (strict equality)

    • Better handling of Java arrays in modifiable contexts

    • Enhanced casting between BoxLang DateTime and Java Date types

    Better Error Handling

    • Improved error messages in expression interpreter

    • Enhanced attempt.orThrow() handling

    • Better parsing errors for unclosed brackets

    Array & Collection Enhancements

    • ArrayResize now accepts long values

    • Added missing max and min member functions

    • Fixed WriteDump errors on null array values

    Query Improvements

    • Fixed query context issues in nested loops

    • Resolved queryDeleteColumn data integrity issues

    • Better handling of query serialization/deserialization

    • Support for queryObject.columnnames

    Regular Expression Enhancements

    • Fixed back reference handling (including references > 9)

    • Improved upper/lower case escapes in replacement text

    • Better support for complex regex patterns

    🐛 Major Bug Fixes

    JDBC & Database

    • Fixed race conditions in threaded query execution

    • Resolved nested transaction issues

    • Fixed savepoint name length limitations

    • Improved query caching with Redis integration

    File Operations

    • Fixed cfcontent file corruption issues

    • Better handling of relative file paths in fileRead

    • Improved MIME type detection with strict mode

    • Enhanced multipart form handling

    Session Management

    • Fixed SessionRotate and SessionInvalidate JSessionId handling

    • Better SameSite cookie attribute handling

    • Improved session shutdown cache interceptor

    Component & Scope Handling

    • Fixed private static struct function access

    • Resolved scope access issues in custom tags

    • Better handling of thisComponent scope (renamed from thisTag)

    Serialization & Casting

    • Fixed DeSerializeJSON strictMapping parameter

    • Better handling of Java primitive arrays

    • Improved object serialization in various contexts

    🏗️ Architectural Changes

    Dependency Updates

    • Updated Jackson-jr to latest patch version

    • Bumped semver4j from 5.8.0 to 6.0.0

    • Updated Apache Commons FileUpload to jakarta-servlet5

    • Updated Commons Text from 1.13.1 to 1.14.0

    Code Organization

    • Refactored customTagsDirectory to customComponentsDirectory (with backward compatibility)

    • Renamed thisTag scope to thisComponent scope for consistency

    • Removed external JavaParser dependencies unless explicitly checked

    Base64 & Encoding

    • Improved base64 string handling with padding tolerance

    • Better UTF-8 encoding support for multipart form data

    • Enhanced encoding handling across the platform

    📚 New Documentation

    We've significantly expanded our documentation with comprehensive new guides:

    • - Complete miniserver setup and configuration

    • - In-depth component development

    • - Database transaction management

    • - Working with XML in BoxLang

    Comprehensive Asynchronous Programming Documentation

    • - Thread pool management

    • - Future-based programming

    • - Chaining async operations

    🎯 CFML Compatibility Improvements

    This release includes numerous CFML compatibility enhancements:

    • Better parseDateTime compatibility with ACF

    • Improved handling of date masks and formatting

    • Enhanced numeric operations and casting

    • Better list BIF consistency across multi-character delimiters


    Release Notes

    Improvement

    Update the feature audit tool with the correct modules

    Remove all JavaParser dependencies externally unless you check if it exists

    improve error message on expression interpreter

    Handle attempt.orThrow() better

    Support some more natural date parsing masks which aren't case sensitive

    lookup of custom componets and classes refactoring for performance

    String performance and optimizations improvements for toScript() bif

    Bump org.semver4j:semver4j from 5.8.0 to 6.0.0

    avoid calling unputStream.available() due to FusionReactor bug

    make module classes visible to context classloader

    Update jackson-jr to latest patch

    skip type coercion for === operator

    default non-existent request bodies to an empty string

    Ignore extra padding on base64 encoded strings

    remove JSON serialization limit

    Improve JSON serialization of throwable

    org.apache.commons:commons-fileupload2-jakarta-servlet5

    Re-organize and add validation to loaded miniserver config options

    Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0 (#288)

    Bump commons-io:commons-io from 2.19.0 to 2.20.0

    Re-instate parsing errors for unclosed brackets

    Bug

    Documentation of Image module

    BX Compiler Issues

    Cast error on BoxFuture.all()

    Can't cast a Java Array to a modifiable Array.

    DateFormat vs TimeFormat vs DateTimeFormat BIF Separations

    Private static struct function not found

    round does not accept second argument for number of places, despite being documented

    Issue with clone when using zonedatetimes

    dump template for Java class not handling static field

    java boxpiler not always compiling array literal

    JDBC - Unable to execute query in nested transaction unless outer transaction has a query that executes first

    JDBC - Failed to set savepoint... is too long

    date mask when parsing string dates

    Fix for this scope access from function in custom tag

    stack overflow in session shutdown cache interceptor

    ToscriptTest not accounting for the timezone of the tests

    ParseDateTimeTest using non timezone tests and would be unpredictable on certain conditions

    bx:component is missing attributecollection argument

    DateTimeCaster does not handle request timezones Zones correctly

    CFML Compat with partial years

    Different return type when calling `getTime()` on `java.util.GregorianCalendar`

    StructSort numeric not sorting on values

    Regular expression back reference is being ignored

    ASM not compiling self-closing custom components the same as Java boxpiler

    outer loop loses query context after inner loop

    Issue with JSON serialization of dates in a BL class

    session cookie - samesite handling

    ArrayResize does not accept long

    WriteDump Error on Null Array Values

    Compat: DeSerializeJSON strictMapping ignored

    SessionRotate and SessionInvalidate null out JSessionId

    ACF parseDateTime compat

    Casting ortus.boxlang.runtime.types.DateTime to java.util.Date

    outer for loop loses query context with inner for loop

    queryDeleteColumn deletes the column but not the data from the query object

    fileRead should handle relative files

    now isn't being cast to java.util.Date

    Grouped looping is not showing expected output when not inner grouping

    JDBC - Query caching into bx-redis throws 'failed to serialize object'

    Httpparam formfield is adding a break line on values when multipart is true

    FileGetMimeType with strict should be based on file content

    Deserialized Query Columns are Invalid because they no longer contain query reference

    DateTime does not properly deserialize because formatter is transient

    val() with negative value returns 0

    regex replacement backreferences greater than 9 don't wor

    regex upper/lower case escapes should apply to all replacement text

    JDBC race conditions present in threaded (or Future-ed) query execution

    Zip includes target directory as first level parent.

    queryObject.columnnames not supported

    cfcontent is causing files to be corrupted

    java double[] not handled by writeoutput / SerializeJSON

    `max` and `min` member functions missing

    list BIFs have inconsistent support for multiCharacterDelimiter

    PlacehbolderReplacer was not using the String Caster when dealing with map bindings.

    Servlet: Missing UTF-8 encoding for form fields with multipart/form-data

    New Feature

    .env support for the BoxLang miniserver

    implement nested grouped output/looping

    Add zipparam support for ZIP functionality

    BoxLang mappings need to have an extra definition: external which defaults to false

    runAsync is the alias, the main method is asyncRun() so we can use the `asyncX` namespace

    asyncAll, asyncAllApply, asyncAny bifs and constructs for parallel programming

    Add simple health checks for miniserver, especially for container based loading

    Basic hidden file protection in MiniServer

    Task

    Refactor customTagsDirectory to customComponentsDirectory and add shim to support it

    Rename thisTag scope to thisComponent scope for consistency and transpile the old scope

    Performance optimized - Leverages modern JVM concurrency patterns under the hood

  • Dedicated logging - Separate async.log and scheduler.log files for complete observability of async operations

  • asyncAny() - Race multiple operations and get the fastest result—perfect for timeout patterns and redundant services

  • return types
    property

    Updated Commons IO from 2.19.0 to 2.20.0

    Property Files Guide - Configuration and property management

  • Testing Guide - Testing best practices and frameworks

  • Parallel Computations - CPU-intensive parallel processing

  • Scheduled Tasks - Background task scheduling

  • Asynchronous Programming Guide
    Executors
    BoxFutures
    Async Pipelines
    Parallel Computations
    Scheduled Tasks
    MiniServer Guide
    MiniServer Guide
    Components Guide
    Transactions Guide
    XML Processing Guide
    Asynchronous Programming Overview
    Executors
    BoxFutures
    Async Pipelines
    BL-1517
    BL-1518
    BL-1565
    BL-1566
    BL-1571
    BL-1577
    BL-1579
    BL-1581
    BL-1601
    BL-1604
    BL-1618
    BL-1625
    BL-1636
    BL-1642
    BL-1647
    BL-1648
    BL-1651
    BL-1653
    BL-1656
    BL-1657
    BL-1659
    BL-1214
    BL-1367
    BL-1415
    BL-1496
    BL-1539
    BL-1548
    BL-1555
    BL-1562
    BL-1564
    BL-1567
    BL-1568
    BL-1569
    BL-1570
    BL-1573
    BL-1575
    BL-1578
    BL-1580
    BL-1582
    BL-1584
    BL-1585
    BL-1587
    BL-1588
    BL-1589
    BL-1592
    BL-1593
    BL-1594
    BL-1596
    BL-1597
    BL-1598
    BL-1606
    BL-1607
    BL-1610
    BL-1611
    BL-1612
    BL-1613
    BL-1615
    BL-1616
    BL-1620
    BL-1621
    BL-1622
    BL-1623
    BL-1624
    BL-1626
    BL-1627
    BL-1628
    BL-1629
    BL-1630
    BL-1632
    BL-1633
    BL-1634
    BL-1635
    BL-1639
    BL-1641
    BL-1652
    BL-1658
    BL-842
    BL-1464
    BL-1515
    BL-1525
    BL-1595
    BL-1609
    BL-1654
    BL-1655
    BL-1576
    BL-1637
    // Run multiple operations in parallel
    results = asyncAll( [
        () => fetchUserData( userId ),
        () => fetchOrderHistory( userId ),
        () => fetchPreferences( userId )
    ] );
    
    // Apply function to multiple inputs in parallel
    processedData = asyncAllApply(
        [ "file1.txt", "file2.txt", "file3.txt" ],
        ( file ) => processFile( file )
    );
    
    // Get the first completed result
    fastestResult = asyncAny( [
        () => callService1(),
        () => callService2(),
        () => callService3()
    ] );
    
    // Powerful async pipelines - chain operations naturally
    userPipeline = asyncRun( () => fetchUser( userId ) )
        .then( user => validateUser( user ) )
        .then( user => enrichUserData( user ) )
        .then( user => cacheUser( user ) )
        .onSuccess( user => auditLog( "User processed: #user.id#" ) )
        .onError( error => logError( "Pipeline failed: #error.message#" ) );
    
    // Advanced scheduling with natural syntax
    schedule.task( "data-cleanup" )
        .call( () => cleanupExpiredData() )
        .everyDayAt( "02:00" )  // Every day at 2 AM
        .timezone( "America/New_York" )
        .onSuccess( result => writeLog( "Cleanup completed: #result.recordsDeleted# records" ) )
        .onError( error => sendAlert( "Cleanup failed: #error.message#" ) );
    
    // Weekly reports on business days
    schedule.task( "weekly-report" )
        .call( () => generateWeeklyReport() )
        .onFridays( "17:00" )
        .withNoOverlaps()
        .onSuccess( report => emailReport( report ) );
    
    // One-time delayed execution
    schedule.task( "send-reminder" )
        .call( () => sendReminderEmail( userEmail ) )
        .delay( 1, "hours" )  // Execute in 1 hour
        .onSuccess( () => writeLog( "Reminder sent successfully" ) );
    
    // Complex parallel data processing pipeline
    reportData = asyncRun( () => fetchRawData() )
        .then( data => asyncAllApply( data, row => processRow( row ) ) )
        .then( processedRows => aggregateResults( processedRows ) )
        .then( summary => generateReport( summary ) )
        .onSuccess( report => emailReport( report ) )
        .get();  // Block and get the final result
    // Default External Mapping
    this.mappings[ "myInternalMapping" ] = "/abc/internal/path";
    this.mappings[ "myExternalMapping" ] = {
        path: "/abc/external/path",
        external: true  // Indicates this mapping CANNOT be accessed via URL
    };
    
    ### Enhanced ZIP Functionality
    
    New `zipparam`support provides fine-grained control over ZIP operations:
    
    ```js
    zip( action="zip", file="myarchive.zip" ) {
        zipparam( source="folder1/", prefix="backup/" );
        zipparam( source="file.txt", entrypath="documents/readme.txt" );
    }
    bx:loop( query="salesData", group="region,quarter" ) {
        writeOutput( "<h2>#region# - #quarter#</h2>" );
    
        bx:loop() {
            writeOutput( "<p>Sale: #amount# on #date#</p>" );
        }
    }
    # .env file
    DATABASE_URL=jdbc:mysql://localhost:3306/mydb
    API_KEY=your-secret-key
    DEBUG_MODE=true