Wednesday, January 23, 2008

I am just a lazy programmer in love with my reflection

Okay, so I am not really narcissistic. Though I am a lazy programmer. Sometimes when I am coding, I want to get a quick glimpse of a java object's properties, without hand coding all of the method names. Enter my love of reflection.

The java.lang.reflect (reflection) class allows you to dynamically access an object's properties, methods, etcetera. So being the lazy programmer that I am, I often use it to do a quick dump of an object's simpler methods. Your basic getX() or boolean isSomething() methods.

Take my previous post on using POI to get MS Word metadata. I did not actually type the code for outputting the summary properties. I used reflection. (Told you I was lazy). Not that you would want to, but you could probably recreate the entire API for a class using only reflection.

Here is an example using iText's PdfReader class. I picked it mainly because it has a few interesting methods and will work with both MX7 and CF8. Though to limit the output, the example only grabs methods that start with "get" or "is" and does not display a full cfdump. But you could certainly change that to get more detail.


<!--- read in a PDF file using iText --->
<cfset filePath = ExpandPath("./SimpleRegistrationForm.pdf")>
<cfset reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init(filePath)>
<cfset Modifier = createObject("java", "java.lang.reflect.Modifier")>
<cfset methods = reader.getClass().getDeclaredMethods()>

<cfset quickDump( reader )>


<cffunction name="quickDump" returntype="void" output="true" access="public">
<cfargument name="object" type="any" required="true">
<cfset var Local = structNew()>

<cfset Local.modifier = createObject("java", "java.lang.reflect.Modifier")>
<cfset Local.methods = arguments.object.getClass().getDeclaredMethods()>

<cfloop from="1" to="#arrayLen(Local.methods)#" index="Local.m">
<cfset Local.currMethod = Local.methods[Local.m]>

<!--- find only simple, PUBLIC methods with zero arguments --->
<cfset Local.isSimpleMethod = reFindNoCase("^(get|is)", Local.currMethod.getName() )>
<cfset Local.hasZeroArguments = NOT arrayLen( Local.currMethod.getParameterTypes() )>
<cfset Local.isPublic = Local.currMethod.getModifiers() EQ Local.modifier.PUBLIC>

<!--- if this is a valid method, display the results --->
<cfif Local.isPublic AND Local.isSimpleMethod AND Local.hasZeroArguments>
<cfoutput>
<cftry>
<!--- call the method and get the returned value --->
<cfset Local.results = Local.currMethod.invoke( arguments.object, javacast('null', ""))>
<cfif NOT structKeyExists( Local, "results")>
<cfset Local.results = "(null)">
</cfif>

<b>method name: </b> #Local.currMethod.getName()#
<b>value:</b> #Local.results.toString()#
<cfcatch>
<b> error: </b>
<cfif structKeyExists(cfcatch, "cause")>
#cfcatch.cause.type# : #cfcatch.cause.message#
<cfelse>
#cfcatch.type# : #cfcatch.message#
</cfif>
</cfcatch>
</cftry>
</cfoutput>
<br>
</cfif>
</cfloop>
</cffunction>

0 comments:

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep