Skip to main content
Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.

Listing All Classes In A Jar File Using ColdFusion

By Ben Nadel on
Tags: 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.



Reader Comments

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 :-)