CFCatch Can Target Explicit Java Exception Types Even With JavaLoader In Lucee 5.3.2.77
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:
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:
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.
Want to use code from this post? Check out the license.
Reader Comments
Just out of interest. What are Jedi's Pools? It sounds like something that Raymond Camden [Star Wars] should be writing about!
@Charles,
Ha ha ha,
Jedis
is just a Java client for Redis (Java Redis -> Jedis) :DAnd, 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.
Thanks for this explanation. Very interesting!
Can you query this in-memory Database using SQL, or does it have a special language? I might try this out! Sounds fun...
@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.