Skip to main content
Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.

From ColdFusion 10 To ColdFusion 2021 - Preparing For Some Blog Love

By Ben Nadel on
Tags: ColdFusion

UPDATE - Nov 3, 2021: When I first published this article, I was running on Adobe ColdFusion 2018. However, right after publishing it, I asked my hosting provider to bump me up to ColdFusion 2021. As such, I've updated the article to reflect this new jump in features.


This blog is hella old. It started back in 2006 on Macromedia ColdFusion MX 7. At some point, it was updated to ColdFusion 10, where it remained for the better part of a decade. Recently, I updated it to Adobe ColdFusion 2018. But, the underlying code is still hella old and in much need of some love and tenderness. I'd like to put some time into modernizing the internals. But, before I do that, I need to get a sense of what "modernization" even means when moving from ColdFusion 10 to ColdFusion 2018. This post is really a note to self that refreshes my brain as to what functionality is now available to me in the current Adobe ColdFusion 2018 (nay, 2021) install.

What follows is not an exhaustive list - it's a cursory look at the "What's New" documentation, paired down to the features that will likely hold value for my particular style of programming.

What's New in Adobe ColdFusion 11

  • getSafeHtml() - sanitizing HTML using the OWASP AntiSamy project.

    ASIDE: My blog currently using the AntiSamy project directly with the JavaLoader project for loading JAR files on-the-fly.

  • Elvis operator (?:) for null coalescing.

    CAUTION: On the Modernize or Die podcast, [Brad Wood][brad-cood] is constantly railing against the Elvis operator in Adobe ColdFusion for being so buggy that he can't even really use it. As such, I'll approach this with caution optimism. It's definitely a feature that I use all the time in Lucee CFML.

  • Member functions on native data-types.

  • Proper key-case preservation when serializing native data-types as JSON (JavaScript Object Notation). This has long been a massive pain in ColdFusion, making JSON almost unusable in many ways.

  • Full support for ColdFusion tags in CFScript block:

    • withoutbody();
    • withbody() { ... }
    • cf_withoutbody();
    • cf_withbody() { ... }
    • prefix:customtag();
    • prefix:customtag() { ... }

    ASIDE: I love that Adobe ColdFusion supports prefix-based ColdFusion custom tags in CFScript. At this time, Lucee CFML doesn't support this. And, I love using custom tags, especially for my HTML Email DSL.

  • Built-in Functions (BIFs) as first-class citizens. Meaning, the function references can be passed-around as references.

  • queryExecute() - executing SQL queries in CFScript. When possible, I want to use script-based components. This is not as good as using tag-islands in Lucee CFML; but, I'll get used to it.

  • More Array methods, arrayMap(), arrayReduce().

  • More Struct methods, structMap().

What's New in Adobe ColdFusion 2016

  • Safe navigation (?.) operator to help avoid null-pointer exceptions in a deep-object expression.

    ASIDE: This is often used in conjunction with the Elvis operator to provide a default for complex expressions, ( a?.b?.c ?: "default" ).

  • Ordered Structs / Collections using [:] or [=] syntax. This is really helpful when dealing with MongoDB collections in which the order of keys is actually meaningful to the underlying document query.

  • passArrayByReference - application setting that allows Arrays to be passed-by-reference. Historically, arrays have been passed-by-value in ColdFusion (which is less performant).

  • searchImplicitScopes - application setting that limits the number of scopes to be searched when referencing un-scoped variables.

  • More Query methods, querySort(), queryFitler(), queryMap(), queryReduce().

  • valueArray() - getting a set of query column values as an array.

  • item attribute in CFLoop that stores the value in an array loop. Can be used in conjunction with index to get both the value and index.

  • encodeFor attribute in CFOutput tag. This automatically applies the given encoding to all interpolation expressions in the output block.

  • replace() can now take a closure.

What's New in Adobe ColdFusion 2018

  • Negative indices on Arrays, [-1] to access last value.

  • Array slices, [1:6:2] which grabs indices 1-through-6, incrementing the step by 2 each time.

  • Negative indices on Strings, [-1] to access last character.

  • String slices, [1:6:2] - works the same as Array slices.

  • More Array functions, arrayFirst(), arrayLast().

  • More Query functions.

  • enableNULLSupport - application settings that enables full NULL support. This allows you to assign NULL to variables.

  • Proper data-type preservation in Queries. This is particularly important for JSON support.

  • Fat-arrow syntax (() => {}) for closures.

  • Invoke array items as functions, myArray[1]().

  • Chaining data-type member functions.

  • Instantiating ColdFusion components at a given path using new component(pathToCFC). This will be super helpful as I've had to jump through many hoops in the past to invoke ColdFusion components that live above the contextual directory.

  • Creating Java objects using new java(className).

  • Named parameter support for Built-In Functions (BIFs).

  • runAsync() for Future-based asynchronous programming.

What's New in Adobe ColdFusion 2021 via Charlie Arehart

  • BCrypt and SCrypt Password hashing functions.

  • Parallel iteration for Structs and Arrays. I'm super excited about this one. I use this feature in Lucee CFML all the time to download files in parallel. It's a huge value-add!

  • IIFE (Immediately Invoked Function Expressions) - more than anything, this just indicates a modern advance in the syntax capabilities of the language.

  • Spread operator for Functions, Arrays, and Structs - allows an iterable collection to be applied / merged into another collection.

    ASIDE: In addition to spreading a Struct into another Struct, it looks like you can also merge structs by simply including one inside another one as a non-key-value entry.

  • Rest operator - allows the capture of variadic function arguments into an iterable variable.

  • Identity operator (===) - allows the comparison of both value and type in an equality expression.

  • Case-sensitive struct notation (${ key:value }).

    ASIDE: I believe if you have "preserve case" enabled, then you don't even need this notation.

  • Destructuring Arrays and Structs - honestly, I'm not a fan of destructuring. I find this style of code to be hard to read, and tends to over-tax the "compiler" in my head. The same is true with the new "property shorthand" syntax. It all falls under the "too clever" category for me. That said, it's good to know that it's here.

  • Dynamic switch statements - this can be great when the case values point to expressions; though, it looks like the supported functionality is way more dynamic than I would recommend using.

  • Query returnType="array" - returns an Array-of-Structs instead of a Query object.

  • New Array methods, ArrayPush(), ArrayPop(), ArrayShift(), and ArrayUnshift() - bringing things closer to JavaScript syntax, which is always nice!

  • Base64Url support for encoding / decoding binary values - this is becoming a popular choice for anything that needs to be passed safely via the URL.

  • Writing Java code right inside our CFML - I'm super curious about this feature. One of the things that has held me back over the years is not feeling confident in extending ColdFusion code with custom Java classes. This might change everything!

    ASIDE: It seems the one thing that Adobe ColdFusion is still lacking when compared to Lucee CFML is the ability to load JAR files on-the-fly via the createObject() function. It looks like I'll still be using the JavaLoader project to do that in Adobe ColdFusion 2021.

Again, this is not meant to be an exhaustive list of features added in the various ColdFusion releases - this was just a subset of the features that appealed to me (and will likely be helpful as I incrementally update my blog architecture). A lot of my blog code is still tag-based. So, one of the main improvements that I hope to make is to move as much of it as possible to CFScript. Which, should be relatively easy with the full-tag support in the language.

As I was Googling for this stuff, I stumbled upon a page on the CFDocs site that lists features improvements by version. And, of course, Charlie Arehart always has a wealth of information regarding the various ColdFusion releases and their hidden gems.



Reader Comments

Currently talking to my hosting provider to see if I can upgrade to Adobe ColdFusion 2021. I mean, might was well make the biggest jump I can, right?!

Reply to this Comment

Great list. I love how far CF has come. Two questions...

  1. who is your host provider?
  2. why not transition to Lucee too while you're at it?
Reply to this Comment

@Chris,

So, I use Hostek. And, when I was doing the upgrade from ColdFusion 10 to 2018, I did ask if I could change over to Lucee since that's what I use at work. They said that they do have Lucee hosting and they support it; but, that their team was much better at managing Adobe ColdFusion. So, I just decided to keep on ACF. Plus, I figured it might be nice to have two platforms in my life - for a bit of variety 😜

Reply to this Comment

Woot! Hostek is gonna upgrade me to ACF 2021. So, when that is done, I'll update this list with whatever new goodies come in 2021.

Reply to this Comment

Sounds good! I've always been happy with Hostek. The great thing about moving to Lucee is that you can get more resources for less $$, but that might not be a huge selling point in your case.

Reply to this Comment

@All,

Now that this blog is running on Adobe ColdFusion 2021, I've updated the blog post to reflect some of the new features that I want to explore in my code.

That said, I'm still missing the ability to load JAR files on-the-fly like you can do in Lucee CFML's createObject() method. And, of course, tag islands is still a huge feature gap that revolutionized my CFML code.

Reply to this Comment

Tag islands are the coolest thing I've seen that I'd love to incorporate into my code. I'd love to migrate to Lucee...not just for this feature either ðŸĪ“

Reply to this Comment

@Chris,

ðŸ’ŊðŸ’ŊðŸ’Ŋ I'm going to have to learn to like queryExecute() to run SQL in CFScript. But, I'd so much rather be using <cfquery> and <cfqueryparam> inside a tag island 😭

Reply to this Comment

Ben, really glad to see the addition of 2021. But as for the lack of the ability to name a jar on createobject/cf object, I hope you and readers are at least aware that you can load jars on a per-app basis (this.javasettings.loadpath), rather than rely otherwise solely on the old notion of having to load jars into cf's classpath.

That's a great half-way point, until Adobe may take on the other feature. Many have leveraged the app settings approach since it came out in cf10 (2012), which is indeed about the same time PRs in the javaloader github repo started to tail off substantially. But it seems worth at least mentioning, as some may NOT know about it.

Reply to this Comment

@Charlie,

You raise a good point. I think in the past, I've shied away from the app-level Java settings only because I've run into version conflicts between different libraries (since they all go into the root Class Loader, from my understanding). But, it's definitely good for something that truly stands on its own, such a custom Java classes that you create for your own project.

Reply to this Comment

I'm not sure about that, Ben. There would certainly be no impact outside the application (that's the main point of it being an app setting), but if you may mean that the classes/jars in the "root classloader" would conflict with those named in the javasettings.loadpaths (I forgot the "s") in my last comment), I will note that there's another setting in that javasettings for loadColdFusionClasspath, a boolean.

If instead one wanted to use both of those (classes in the named new classpath AND classes from CF's own classpath), whether in your calling them with createobject/cfobject or by CF's own internal loading of java classes to run your code, I suppose there could be conflicts, sure. (I suspect we could dig in to find which get loaded FIRST in the classpath within the app. I'd expect the one discussed here would take precedence, but that may not be enough to prevent some conflicts.)

BTW, for any interested in still more on this, I should have added that the docs for this (and other things that javaloader did, like providing a dynamic proxy) are at https://helpx.adobe.com/coldfusion/developing-applications/using-web-elements-and-external-objects/integrating-jee-and-java-elements-in-cfml-applications/enhanced-java-integration-in-coldfusion.html

Reply to this Comment

Oh, and thanks for the mention (in the section title for your CF2021 "new feature" section). I gather you got that info from my talk, "hidden gems in cf2021". And of course you had acknowledged my hidden gems talks in your original version of this post--and thanks for that, of course.

Yep, folks interested in still more about differences in the various recent CF versions will find that I covered most of these (and perhaps some more coding changes) in those talks, which are all at carehart.org/presentations, specifically. Note that in those talks I also discuss far MORE than just coding changes, but I understand why that's the limit of focus in Ben's post here.

And thanks for it!

Reply to this Comment

@Charlie,

Sorry for my lack of clarity 🙃 what I meant by "conflict" is that I might want to load two different 3rd-party libraries that respectively have dependencies that conflict with each other. Imagine I have 2 libraries that both use com.bennadel.widget; but, with two different version that are incompatible:

  • Dependency A ← com.bennadel.widget@2.0.1
  • Dependency B ← com.bennadel.widget@3.0.1

I believe that If I try to load both of those version in the Application-specific JAR paths, only one of them will actually be loaded. And I might end up making the wrong version available to one of the dependencies.

Reply to this Comment

Oh. Well, yeah. I guess so. :-) Sounds like a bit of an edge case, but if you or others ever trying it may find it doesn't work as expected, that would be something to certainly raise to Adobe at tracker.adobe.com (where example code and even java class files can be uploaded as attachments).

While some think of tracker as a place "where bug reports go to die", the fact is that each CF update (every few months) tends to have a few dozen bug fixes. So they really do look to tracker, and I can attest to seeing recent activity on many reported bugs. (Granted, someone may find that THEIR bug report languishes--as I can attest has happened to me also on occasion.)

As the saying goes, "it's better to light one candle than to curse the darkness". :-)

Reply to this Comment

@Charlie,

You might be right - maybe it is more of an edge-case than I think it is. I feel like I have been burned by conflicting "http client" libraries somewhere. Or "commons logging" or "commons connection pool" versions. But, maybe I should just try to use the app-level JARs until I can't ; and then, worry about it then.

I would love to be able to get rid of as many dependencies as I can.

Reply to this Comment

Seeing that you just upgraded to CF2021, dropping a tip if you run into Java errors such as "java.lang.reflect.InaccessibleObjectException" that I got when I tried out your GetTextDimensions function after likewise upgrading to CF2021. The JVM needs a couple arguments to get the function working again:
--add-opens=java.desktop/sun.java2d=ALL-UNNAMED --add-opens=java.desktop/sun.font=ALL-UNNAMED

Something about java objects not being public, it's all mumble-jumble to me but I was able to figure out the means for adding jvm args to work around it.

I couldn't find a blog post on issues upgrading to CF2021 but this one is close. One topic is weird issues that crop up with going from old to new, one of which is a "java.lang.reflect.InaccessibleObjectException" error that I received when checking out your GetTextDimensions function. It seems that some Java objects are no longer public trying to access it causes an error. In the case of your CFC, it was on the following line when accessing GetGraphics()
<cfset LOCAL.Graphics = ImageGetBufferedImage( LOCAL.Image ).GetGraphics()/>

The solution is to add the following JVM arguments to open up the java2d & font areas:
--add-opens=java.desktop/sun.java2d=ALL-UNNAMED --add-opens=java.desktop/sun.font=ALL-UNNAMED

Reply to this Comment

Sorry for the dupe stuff, recomposed the message but forgot to erase the old! Scratch out "I couldn't find a ..." and after

Reply to this Comment

@John,

Good tip! I think I either ran into that or something similar. After I upgraded, the site wouldn't load (an error was being thrown in the onApplicationStart() event-handler when trying to instantiate the JavaLoader component. I had to go into the CFIDE and uncheck the security option for "Disable access to internal ColdFusion Java components". It sounds like this may be related to what you're talking about. As with you, this is all sort of mumbo-jumbo to me ðŸĪŠ

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Blog
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.