Skip to main content
Ben Nadel at the New York ColdFusion User Group (Jan. 2010) with: Javier Julio
Ben Nadel at the New York ColdFusion User Group (Jan. 2010) with: Javier Julio

Using Functions As Java Operators In Adobe ColdFusion 2025.0.8

By
Published in

While AI is the marquee feature of Adobe ColdFusion 2025 update 8, one of the minor release notes that really caught my eye was the ability to pass ColdFusion functions into Java to be used as an operator / callback where a "Single Abstract Method" (SAM) it accepted. As much as I absolutely love the fact that we (CFML developers) can dip down into the Java layer for additional super powers, there's always been a bit of an impedance mismatch for more complex interactions at said touch-point. Passing ColdFusion functions as operators is going to be a nice removal of friction.

To demonstrate, let's look at Java's Atomic Integer. The "Atomic" package provides a number of lock-free, thread-safe data structures that provide safe concurrency without heavy(ier)-weight locking mechanics. I often use the Atomic Integer as a thread-safe counter. But, it can do more than just increment and decrement.

For example, it has two methods that accept a SAM operator that implements the mutation logic:

  • updateAndGet( IntUnaryOperator )
  • accumulateAndGet( int, IntBinaryOperator )

Let's try to use both of these method, passing-in a ColdFusion closure, to see how they work. In the following CFML code, we're going to be trying three things:

  1. Call the .incrementAndGet() method which takes no arguments. This is our common base-case and has been available forever in ColdFusion.

  2. Call the .updateAndGet() method which takes a unary operator and returns the next counter value. Our operator will increment the counter by 2 on each call.

  3. Call the accumulateAndGet() method which takes a binary operator and returns the next counter value. Our operator will count up to the given maximum (inclusive) and then reset to 1.

Note that we're not doing anything interesting with our closures — no "dynamic proxy" nonsense — just passing around raw UDFs (User Defined Functions).

<cfscript>

	// ColdFusion language extensions (global functions).
	include "/core/cfmlx.cfm";

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	// The "Atomic" package provides light-weight thread-safe data structures that provide
	// for concurrency without traditional (heavier-weight) locking mechanics. In this
	// case, we'll use the Atomic Integer to create a thread-safe counter.
	counter = new java( "java.util.concurrent.atomic.AtomicInteger" )
		.init( 0 )
	;

	// Base case: no arguments, simple increment.
	echo( "<p> No operator - straightforward java calls. </p>" );

	dump([
		counter.incrementAndGet(),
		counter.incrementAndGet(),
		counter.incrementAndGet(),
	]);


	// Adobe ColdFusion 2025: we can pass a unary (one argument) operator into Java.
	echo( "<p> Unary operator - takes previous value and returns new value. </p>" );

	dump([
		counter.updateAndGet( ( prev ) => prev + 2 ),
		counter.updateAndGet( ( prev ) => prev + 2 ),
		counter.updateAndGet( ( prev ) => prev + 2 ),
	]);


	// Adobe ColdFusion 2025: we can pass a binary (two argument) operator into Java.
	echo( "<p> Binary operator - takes previous/next values and returns new value. </p>" );

	// I increment up until the upper limit (inclusive) is reached, then reset to 1.
	countUpAndThenReset = ( prev, upperLimit ) => {

		return ( prev < upperLimit )
			? ++prev
			: 1
		;

	};

	// Note: 3 is the "upper limit" in this case.
	dump([
		counter.accumulateAndGet( 3, countUpAndThenReset ),
		counter.accumulateAndGet( 3, countUpAndThenReset ),
		counter.accumulateAndGet( 3, countUpAndThenReset ),
		counter.accumulateAndGet( 3, countUpAndThenReset ),
		counter.accumulateAndGet( 3, countUpAndThenReset ),
		counter.accumulateAndGet( 3, countUpAndThenReset ),
		counter.accumulateAndGet( 3, countUpAndThenReset ),
	]);

</cfscript>

It all looks like native, seamless CFML syntax! And when we run this Adobe ColdFusion 2025.0.8 code, we get the following output:

CFDump output showing that passing ColdFusion UDFs into the Java layer were success consumed as unary and binary opeartors in Java.

The ColdFusion user defined functions that we passed into the Java layer were successfully consumed as both unary and binary operators. This is super exciting!

Epilogue On Lexically-Bound Closures

Having nothing to do with ColdFusion specifically, the Atomic callbacks in this demo are intended to be "side-effect free". Meaning, they are pure functions that act solely based on the invocation arguments. That said, since I'm using closures as my operators, they retain the lexically-scoped context. Which means, the operators can technically reach out-of-scope and consume non-local values.

I tried this to see if it works, and it does (not shown in the demo). The operators, executed inside of the Java context, can reach back into the lexically-bound ColdFusion context and consume functions and data. So, that's pretty cool!

Want to use code from this post? Check out the license.

Reader Comments

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel
Managed ColdFusion hosting services provided by:
xByte Cloud Logo