Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Erica Simmons
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Erica Simmons@OhDearErica )

CFCatch Can Target Explicit Java Exception Types Even With JavaLoader In Lucee 5.3.2.77

By Ben Nadel on
Tags: ColdFusion

If you've been in the ColdFusion world for a while, there's a good chance that you've come across Mark Mandel's JavaLoader project. The JavaLoader project wraps a URLClassLoader, making it easy to load external Java Classes right from a set of JAR file-paths. However, there's been one long-standing issue with the JavaLoader, which is that it makes it hard to target explicit Java exception types in your cfcatch blocks. At least, this was true with Adobe ColdFusion. But, given Lucee CFML's tighter integration with Java, I wanted to see if the same issue was present in a Lucee 5.3.2.77 context.

To test this, I'm going to use the JavaLoader to create a Jedis connection pool that has an invalid host name. While the connection pool itself will be instantiated just fine, any attempt to retrieve a connection from the pool will throw a Jedis exception. And, by wrapping such a call in a try/catch, I can check to see what type of errors we can target explicitly in a catch:

<cfscript>

	// Testing to see if we can explicitly catch Java exception types when the error is
	// thrown from a class that was loaded via the JavaLoader (ie, via a URLClassLoader
	// that links to external JAR files).
	try {

		// NOTE: Expected to throw an error.
		jedis = getJedisPool().getResource();

	// Testing to see if we can explicitly catch this Java Exception by type.
	} catch ( "redis.clients.jedis.exceptions.JedisConnectionException" error ) {

		writeOutput( "<p>Caught with <strong>EXPLICIT TYPE</strong></p>" );
		writeDump( var = error, show = "type,message" );

	// .... OR, do we have to fall-back to using "any".
	} catch ( "any" error ) {

		writeOutput( "<p>Caught with <strong>ANY TYPE</strong></p>" );
		writeDump( var = error, show = "type,message" );

	}

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

	/**
	* I return a Jedis connection pool with an INVALID HOST which throw an error when
	* you try to retrieve a resource.
	*/
	public any function getJedisPool() {

		var javaLoaderFactory = new JavaLoaderFactory.JavaLoaderFactory();
		var jedisLoader = javaLoaderFactory.getJavaLoader([
			expandPath( "./commons-pool2-2.6.2.jar" ),
			expandPath( "./jedis-3.1.0.jar" )
		]);

		var config = jedisLoader.create( "redis.clients.jedis.JedisPoolConfig" ).init();	
		var pool = jedisLoader.create( "redis.clients.jedis.JedisPool" ).init(
			config,
			"this_is_not_a_valid_host_and_will_fail"
		);

		return( pool );

	}

</cfscript>

As you can see, we are providing two cfcatch blocks, one that explicitly targets exceptions of type:

redis.clients.jedis.exceptions.JedisConnectionException

And, one that targets exceptions of type:

any

Now, if I run this CFML code in Lucee CFML 5.3.2.77, we get the following browser output:

Lucee CFML is able to target an explicit Java exception type, even when the error is thrown by the JavaLoader.

As you can see, Lucee is able to explicitly target the Jedis exception type, even though the underlying error was thrown by a Java Class that was loaded via the JavaLoader / URLClassLoader.

And, if we run this same CFML code in Adobe ColdFusion 2018, we get the following browser output:

Adobe ColdFusion 2018 is unable to target the explicit Java exception type due to the use of the JavaLoader.

Ad you can see, Adobe ColdFusion 2018 is unable to target the Jedis exception type. This is because the error is being thrown by a Java Class that was loaded via the JavaLoader / URLClassLoader.

I'm really loving how much tighter Lucee's integration with Java appears to be (when compared to Adobe ColdFusion). Not only can it seamlessly load Java classes using createObject(); but, if you are using the JavaLoader project, Lucee can also more explicitly target Java exception types, regardless of where the underlying error is being thrown.



Reader Comments

@Charles,

Ha ha ha, Jedis is just a Java client for Redis (Java Redis -> Jedis) :D

And, if you're curious, Redis is really fast in-memory key-value database. Kind of like a ColdFusion Struct .... if you had 16GB of RAM for that one Struct. At work, we use Redis to do things like cache IP-geolocation, Session state, and rate-limiting status.

Reply to this Comment

@Charles,

Redis has its own set of "commands" that you have to run. Since it's just a key-value store (with some additional Set and Pub/Sub functionality), there's nothing that relates one key to another - not like a relational database.

If you're interested, here are the Redis commands you can run:

https://redis.io/commands

I think you may actually be able to use Redis to power the distributed cache in ColdFusion ... but, I could be remembering that incorrectly.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
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.