Listing All Classes In A Jar File Using ColdFusion
You'll probably never need to do this, but today, I needed to find out what Java classes were available in a given JAR file using ColdFusion. The reason - I was doing some work on my POI Utility ColdFusion custom tags and I needed to see if the version of the POI JAR that ships with ColdFusion supports certain classes. Turns out, this is a fairly straightforward task. I wrapped the functionality up in a ColdFusion user defined function that takes the expanded path to the target JAR file:
<cffunction
name="GetJarClasses"
access="public"
returntype="array"
output="false"
hint="I return an array of classes in the given JAR file (expanded path).">
<!--- Define arguments. --->
<cfargument
name="JarFilePath"
type="string"
required="true"
hint="I am the expanded path of the JAR file."
/>
<!--- Define the local scope. --->
<cfset var LOCAL = {} />
<!--- Create a default array of classes. --->
<cfset LOCAL.Classes = [] />
<!---
Create a JAR input stream to read in the line items
from our target JAR file.
--->
<cfset LOCAL.JarFile = CreateObject(
"java",
"java.util.jar.JarInputStream"
).Init(
CreateObject(
"java",
"java.io.FileInputStream"
).Init(
JavaCast(
"string",
ARGUMENTS.JarFilePath
)
)
)
/>
<!---
Now that we have our JAR file input stream, let's loop
over all the entries looking for CLASS files.
--->
<cfloop condition="true">
<!---
Get the next entry. This might return NULL if the
JAR file has no more classes.
--->
<cfset LOCAL.JarEntry = LOCAL.JarFile.GetNextJarEntry() />
<!---
Check to see if the entry variable exists. If it
does not, then it means the JAR file return NULL
and we are done finding classes.
--->
<cfif StructKeyExists( LOCAL, "JarEntry" )>
<!---
Check to make sure that this entry is not a
directory, but is, in fact a class.
--->
<cfif REFindNoCase( "\.class$", LOCAL.JarEntry.GetName() )>
<!---
Add this class to the array. Since the JAR
file really has a directory structure, let's
replace the path separators with dots.
--->
<cfset LOCAL.ClassName = REReplace(
LOCAL.JarEntry.GetName(),
"[\\/]",
".",
"all"
) />
<!--- Strip off the ".class" path item. --->
<cfset LOCAL.ClassName = REReplaceNoCase(
LOCAL.ClassName,
"\.class$",
"",
"one"
) />
<!--- Add the formatted class name. --->
<cfset ArrayAppend(
LOCAL.Classes,
LOCAL.ClassName
) />
</cfif>
<cfelse>
<cfbreak />
</cfif>
</cfloop>
<!--- Return the array of classes. --->
<cfreturn LOCAL.Classes />
</cffunction>
To call it, you just do this (I had a copy of the installed POI JAR file in the same directory as my test file):
<!--- Get file path to POI installed JAR file. --->
<cfset strJarFilePath = ExpandPath(
"./poi-2.5.1-final-20040804.jar"
) />
<!--- Output the classes. --->
<cfdump
var="#GetJarClasses( strJarFilePath )#"
label="POI 2.5.1 Final Classes"
/>
Running this, we get an array with the following values (abbreviated):
org.apache.poi.ddf.DefaultEscherRecordFactory
org.apache.poi.ddf.EscherArrayProperty
org.apache.poi.ddf.EscherBSERecord
org.apache.poi.ddf.EscherBlipRecord
..... several hundred classes .....
org.apache.poi.util.ShortList
org.apache.poi.util.StringUtil
org.apache.poi.util.SystemOutLogger
Anyway, just thought I would post that in case anyone ever needs this kind of functionality.
Want to use code from this post? Check out the license.
Reader Comments
How is this different then just listing the JAR out with cfzip?
I never really play around with JAR files much, so this comment could be totally off base, but, could you have not just used the cfzip tag? It accepts a JAR file and you could use the list action and just dumped that out, right? or am i missing the point? It's Friday so my brain has shut of ffor the weekend :-)
@Todd - beat me to it :-)
@Todd, @Simon,
Oh snap, I totally forgot that CFZip could read JAR files :)
Thanks guys; amends have been made:
www.bennadel.com/index.cfm?dax=blog:1373.view