DEV Community

Michael Born
Michael Born

Posted on • Updated on • Originally published at michaelborn.me

How to Get the Version of Any Java Package from CFML

The Apache POI library is an awesome tool for messing with spreadsheets. You can read spreadsheet data, get header rows, total row count, all sorts of wacky stuff. Julian Halliwell's excellent spreadsheet-cfml library uses it to great effect.

But when I try to use Apache POI standalone, I got an error that a method didn't exist:

No matching Method/Function for org.apache.poi.hssf.usermodel.HSSFSheet.getTables() found
Enter fullscreen mode Exit fullscreen mode

It would seem that Lucee bundles an older version of Apache POI by default. (UPDATE: Turns out this is only present due to the Apache Tika bundle, which is shipped with Lucee. Thanks Julian Halliwell for that tip!

But what version would that be?

We could easily find out from the Lucee admin page, of course. Provided it is enabled.

But why not try to grab the POI bundle version in code? From our CFML?

Reading a Java Package Version in Lucee

It all starts with the java class:

createObject( "java", "org.apache.poi.hssf.usermodel.HSSFSheet" )
Enter fullscreen mode Exit fullscreen mode

We then grab the java classloader tied to this class:

createObject( "java", "org.apache.poi.hssf.usermodel.HSSFSheet" )
                        .getClass()
                        .getClassLoader()
Enter fullscreen mode Exit fullscreen mode

Once we have that, we need to grab the OSGI bundle:

createObject( "java", "org.apache.poi.hssf.usermodel.HSSFSheet" )
                        .getClass()
                        .getClassLoader()
                        .getBundle()
Enter fullscreen mode Exit fullscreen mode

And finally, grab the version as a string:

var version = createObject( "java", "org.apache.poi.hssf.usermodel.HSSFSheet" )
                        .getClass()
                        .getClassLoader()
                        .getBundle()
                        .getVersion()
                        .toString()
Enter fullscreen mode Exit fullscreen mode

Voila! We have our package version! It seems Lucee ships with Apache POI 2.5.1, released in November 2005. Wow.

UPDATE: Using Lucee's BundleInfo() method

Julian Halliwell (author of the awesome Spreadsheet CFML library) pointed out that Lucee has a bundleInfo() function which does the same thing:

Great post! Lucee has a BundleInfo() BIF which also returns other useful info. - Julian Halliwell, @cfsimplicity

Using bundleInfo() would look something like this:

var version = createObject( "java", "org.apache.logging.log4j.LogManager" ) ).version;
Enter fullscreen mode Exit fullscreen mode

Honestly, this is much nicer than my implemen

Reading a Java Package Version from Adobe ColdFusion

However, in Adobe CF (ACF) this fails because ACF does not architecture packages via OSGI. (Not to my knowledge, that is.) We need to find another method… and it turns out reading package details is even simpler in Adobe.

First, we instantiate the Java Package library:

createObject( "java", "java.lang.Package" );
Enter fullscreen mode Exit fullscreen mode

From there, we get the Apache POI package:

createObject( "java", "java.lang.Package" )
            .getPackage( "org.apache.poi" );
Enter fullscreen mode Exit fullscreen mode

Once we have the POI package, we can grab the implementation version:

var version = createObject( "java", "java.lang.Package" )
                    .getPackage( "org.apache.poi" )
                    .getImplementationVersion();
Enter fullscreen mode Exit fullscreen mode

And that’s it!

A Cross-Engine Solution

Sadly, neither of these solutions work in both Lucee and Adobe ColdFusion due to the differences in Java package bundling approaches between the two engines.

The best we can get would be something like this:

/**
 * Grab installed version of the bundled Apache POI library.
 */
public string function getApachePOIVersion(){
    if ( server.system.keyExists( "lucee" ) ){
        createObject( "java", "org.apache.poi.hssf.usermodel.HSSFSheet" )
            .getClass()
            .getClassLoader()
            .getBundle()
            .getVersion()
            .toString()
    } else {
        return createObject( "java", "java.lang.Package" )
                            .getPackage( "org.apache.poi" )
                            .getImplementationVersion();
    }
}
Enter fullscreen mode Exit fullscreen mode

Sadly, I see little hope for a cross-engine solution that works generically on package names. In Adobe you can grab the package version by package name… but in Lucee you must search for a specific package class.

The POI Version Class

Caveat: Apache POI ships with a “Version” class in versions 3.x. So my example is a bit pointless for Apache POI v3 and newer. If you’re on ACF 10+, you can use the provided Version class to grab the version - no Java Package gymnastics required:

    createObject( "java", "org.apache.poi.Version" ).getVersion()
Enter fullscreen mode Exit fullscreen mode

That’s not the point of this blog post, though. This post aims to assist you in reading the installed version of any Java package - not just those with a handy my.package.Version class.

Till next time!

Top comments (1)

Collapse
 
bennadel profile image
Ben Nadel

I think your first bundleInfo() code snippet is missing something. It has one open-parens, but two closing-parens. Like part of the call-structure got stripped-out.