Finding Available Java Constructors / Methods For ColdFusion Objects

Posted August 17, 2006 at 3:57 PM by Ben Nadel

Tags: ColdFusion

I am becoming increasingly interested in the Java world that lives below the surface of ColdFusion. She seems like a really sexy girl and I like playing with her bits. The problem is, I don't really know what is available. You can call GetMetaData() on objects and it gives you some insight, but not everything you need to know. To overcome the limitation of GetMetaData(), I have developed two functions to help in my exploration:

GetJavaClassMethods()
GetJavaClassMethodParameters()

While the first method above is the *real* method of use, let's look at the second method first:

GetJavaClassMethodParameters()

This method takes only one argument, a Java method definition. It takes this definition and pulls out the parameters that need to be passed in and returns them as a comma-delimited list. This is sooo key when compared to GetMetaData() because it shows you how overloaded methods are different from one another.

Let's take a look at the method:

  • <cffunction
  • name="GetJavaClassMethodParameters"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns the arguments that are required for the given Java method call.">
  •  
  • <!--- Define arguments. --->
  • <cfargument name="Method" type="any" />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = StructNew() />
  •  
  • <!--- Get the parameters. --->
  • <cfset LOCAL.Parameters = ARGUMENTS.Method.GetParameterTypes() />
  •  
  • <!--- Set up the results. --->
  • <cfset LOCAL.ParamList = "" />
  •  
  • <!--- Loop over the parameters. --->
  • <cfloop
  • index="LOCAL.ParameterIndex"
  • from="1"
  • to="#ArrayLen( LOCAL.Parameters )#"
  • step="1">
  •  
  • <cfset LOCAL.ParamList = ListAppend(
  • LOCAL.ParamList,
  • LOCAL.Parameters[ LOCAL.ParameterIndex ].GetName()
  • ) />
  •  
  • </cfloop>
  •  
  • <!--- Space out the parameters (visual difference only). --->
  • <cfset LOCAL.ParamList = Replace(
  • LOCAL.ParamList,
  • ",",
  • ", ",
  • "ALL"
  • ) />
  •  
  • <!--- Return the parameter list. --->
  • <cfreturn LOCAL.ParamList />
  • </cffunction>

This function might return, as an example, something like "int, java.lang.String". This would denote that to properly call the Java method, you would need to pass it an integer and a string value (in that order). Remember to use JavaCast() when calling Java methods.

But, that's just a small part of it. Let's take a look at the parent function:

GetJavaClassMethods()

This takes a ColdFusion object and returns all of its available Java methods. I don't think all of these can be used exactly - it takes a bit of trial to get it right. The method list is returned in a query that has both public methods AND constructors as well as the parameter list discussed above and the return types.

  • <cffunction
  • name="GetJavaClassMethods"
  • access="public"
  • returntype="query"
  • output="false"
  • hint="This takes a ColdFusion object and returns a query of all the available Java methods including constructors.">
  •  
  • <!--- Define argument. --->
  • <cfargument name="CFObject" type="any" required="yes" />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = StructNew() />
  •  
  • <!--- Create a query for the methods. --->
  • <cfset LOCAL.MethodQuery = QueryNew(
  • "name, return_type, parameters, is_constructor"
  • ) />
  •  
  • <!--- Get an array of all constructors of the class object. --->
  • <cfset LOCAL.ClassConstructors = ARGUMENTS.CFObject.GetClass().GetConstructors() />
  •  
  • <!--- Get an array of all PUBLIC methods of the class object. --->
  • <cfset LOCAL.ClassMethods = ARGUMENTS.CFObject.GetClass().GetMethods() />
  •  
  • <!--- Add enough rows to the query for each method. --->
  • <cfset QueryAddRow(
  • LOCAL.MethodQuery,
  • (
  • ArrayLen( LOCAL.ClassConstructors ) +
  • ArrayLen( LOCAL.ClassMethods )
  • )) />
  •  
  • <!--- Loop over constructors. --->
  • <cfloop
  • index="LOCAL.ConstructorIndex"
  • from="1"
  • to="#ArrayLen( LOCAL.ClassConstructors )#"
  • step="1">
  •  
  • <!--- Set the name of the method. --->
  • <cfset LOCAL.MethodQuery[ "name" ][ LOCAL.ConstructorIndex ] = LOCAL.ClassConstructors[ LOCAL.ConstructorIndex ].GetName() />
  •  
  • <!--- Set the return type. --->
  • <cfset LOCAL.MethodQuery[ "return_type" ][ LOCAL.ConstructorIndex ] = ARGUMENTS.CFObject.GetClass().GetName() />
  •  
  • <!--- Set the parameters. --->
  • <cfset LOCAL.MethodQuery[ "parameters" ][ LOCAL.ConstructorIndex ] = GetJavaClassMethodParameters( LOCAL.ClassConstructors[ LOCAL.ConstructorIndex ] ) />
  •  
  • <!--- Set this as being a constructor. --->
  • <cfset LOCAL.MethodQuery[ "is_constructor" ][ LOCAL.ConstructorIndex ] = 1 />
  •  
  • </cfloop>
  •  
  •  
  • <!--- Set offset for record count. --->
  • <cfset LOCAL.Offset = (LOCAL.ConstructorIndex - 1) />
  •  
  • <!--- Loop over methods. --->
  • <cfloop
  • index="LOCAL.MethodIndex"
  • from="1"
  • to="#ArrayLen( LOCAL.ClassMethods )#"
  • step="1">
  •  
  • <!--- Set the name of the method. --->
  • <cfset LOCAL.MethodQuery[ "name" ][ LOCAL.Offset + LOCAL.MethodIndex ] = LOCAL.ClassMethods[ LOCAL.MethodIndex ].GetName() />
  •  
  • <!--- Set the return type. --->
  • <cfset LOCAL.MethodQuery[ "return_type" ][ LOCAL.Offset + LOCAL.MethodIndex ] = LOCAL.ClassMethods[ LOCAL.MethodIndex ].GetReturnType().GetName() />
  •  
  • <!--- Set the parameters. --->
  • <cfset LOCAL.MethodQuery[ "parameters" ][ LOCAL.Offset + LOCAL.MethodIndex ] = GetJavaClassMethodParameters( LOCAL.ClassMethods[ LOCAL.MethodIndex ] ) />
  •  
  • <!--- Set this as not being a constructor. --->
  • <cfset LOCAL.MethodQuery[ "is_constructor" ][ LOCAL.Offset + LOCAL.MethodIndex ] = 0 />
  •  
  • </cfloop>
  •  
  • <!--- Perform a query of queries to get proper sorting. --->
  • <cfquery name="LOCAL.SortedMethodQuery" dbtype="query">
  • SELECT
  • name,
  • return_type,
  • parameters,
  • is_constructor
  • FROM
  • [LOCAL].MethodQuery
  • ORDER BY
  • is_constructor DESC,
  • name ASC,
  • parameters ASC,
  • return_type ASC
  • </cfquery>
  •  
  • <!--- Return the full sorted method query. --->
  • <cfreturn LOCAL.SortedMethodQuery />
  • </cffunction>

As you can see, the Method Query is built from the ground-up based on the constructors and then the public methods of the Java class that lives under the passed-in ColdFusion object. To see this in action, the following code:

  • <!--- Build a test string. --->
  • <cfset strTest = "ben nadel is one cool dude!" />
  •  
  • <!--- Dump out the Java methods. --->
  • <cfdump var="#GetJavaClassMethods( strTest )#" />

... would produce the following dump:


 
 
 

 
Java Method List For ColdFusion Objects  
 
 
 

Let's compare that to the standard GetMetaData() dump:


 
 
 

 
GetMetaData() Methods For ColdFusion Objects  
 
 
 

How cool is that?!? My method list is not only alphabetically listed (no worries, it was my pleasure), it shows you what kind of arguments you need to send in. No more guessing! Let's the exploration begin!




Reader Comments

Sep 27, 2006 at 11:16 AM // reply »
30 Comments

Ben, I wanted to let you know I adapted these functions into cfscript (what can I say, I dig the quasi-ECMA thing) and they have been a life saver. I'm working on a gi-normous project to bridge our company's CF-based software with a third-party vendor's system via their web service. Unfortunately, the 3p's documentation is Cruddy McCrap. Their sample code and docs are often out of date or just plain wrong. Now I can see precisely what parameter types are expected. We'll see if this works in comment form, but here it is (if you're curious about some of the variable names I often prefix my variables with a letter to indicate the expected datatype s=string n=numeric k=struct etc)...

<pre>
function getJavaClassMethodParameters(sMethod) {
//Returns the arguments for the given Java method call.
var kLocal = StructNew();
var i = 0;

kLocal.Parameters = Arguments.sMethod.GetParameterTypes();
kLocal.ParamList = "";

for (i=1; i lte ArrayLen(kLocal.Parameters); i=i+1) {
kLocal.ParamList = ListAppend(kLocal.ParamList, kLocal.Parameters[i].GetName());
}
kLocal.ParamList = Replace(kLocal.ParamList, ",", ", ", "ALL");
return kLocal.ParamList;
}

function getJavaClassMethods(oObject) {
//This takes an object and returns a query of all the available Java methods including constructors.
var kLocal = StructNew();
var i = 0;

kLocal.MethodQuery = QueryNew("name, returntype, parameters, isconstructor");
try {
kLocal.ClassConstructors = Arguments.oObject.GetClass().GetConstructors();
}
catch (Any e) {
kLocal.ClassConstructors = ArrayNew(1); // no constructors found.
}
try {
kLocal.ClassMethods = Arguments.oObject.GetClass().GetMethods();
}
catch (Any e) {
kLocal.ClassMethods = ArrayNew(1);
}

if (ArrayLen(kLocal.ClassConstructors) + ArrayLen(kLocal.ClassMethods) gt 0) {
QueryAddRow(kLocal.MethodQuery, (ArrayLen(kLocal.ClassConstructors) + ArrayLen(kLocal.ClassMethods)));
}

for (i=1; i lte ArrayLen(kLocal.ClassConstructors); i=i+1) {
kLocal.MethodQuery["name"][i] = kLocal.ClassConstructors[i].GetName();
kLocal.MethodQuery["returntype"][i] = Arguments.oObject.GetClass().GetName();
kLocal.MethodQuery["parameters"][i] = GetJavaClassMethodParameters(kLocal.ClassConstructors[i]);
kLocal.MethodQuery["is
constructor"][i] = 1;
}
kLocal.Offset = (i - 1);

for (i=1; i lte ArrayLen(kLocal.ClassMethods); i=i+1) {
kLocal.MethodQuery["name"][kLocal.Offset + i] = kLocal.ClassMethods[i].GetName();
kLocal.MethodQuery["returntype"][kLocal.Offset + i] = kLocal.ClassMethods[i].GetReturnType().GetName();
kLocal.MethodQuery["parameters"][kLocal.Offset + i] = GetJavaClassMethodParameters(kLocal.ClassMethods[i]);
kLocal.MethodQuery["is
constructor"][kLocal.Offset + i] = 0;
}

return getJavaClassMethodsQuery(kLocal.MethodQuery);
}

</pre>


Sep 27, 2006 at 11:17 AM // reply »
30 Comments

Oops...well so much for using the <pre> tag. :-)


Oct 3, 2006 at 7:16 AM // reply »
11,238 Comments

Jeremy,

Sorry it has taken me so long to comment on your stuff. I think it's awesome. I especially like the TRY / CATCH blocks you put in. I started to realize that some of these things do throw errors and I have been too lazy to fix it.

Well done dude, well done.


Jan 27, 2007 at 10:45 PM // reply »
92 Comments

Just to let you know in the first code block you don't need to do a replace on the delimiter to space it out. You can simply provide the comma and the space as the delimiter in the listAppend function call. For example, you could do just this: ListAppend("myString", myList, ", ") and it'll work just fine.


Jan 28, 2007 at 8:44 PM // reply »
95 Comments

You are the man! Simple as that :-)


May 8, 2010 at 11:08 AM // reply »
4 Comments

Hey, this is strange! Coldfusion thinks a string is the same as a number...

<cfset cftype="marc bakker is cool-a-dude">
<cfdump var="#getJavaClassMethods(cftype)#">

gives me the same underlying Java constructors and methodnames as

<cfset cftype=5>
<cfdump var="#getJavaClassMethods(cftype)#">

Why is this??

Marc


May 10, 2010 at 10:09 PM // reply »
11,238 Comments

@Marc,

ColdFusion seems to like storing most simple data types as Strings. It will, from time to time, depending on the type of simple value, use a different underlying data type. But, a lot of the time it is a string.

For example:

<cfset x = 1.5 />

... will result in a string. But, this:

<cfset x = createTimeSpan( 1, 12, 0, 0 ) />

... will result in a Double (also 1.5). Also, I believe that now() will return a date/time stamp.


Sep 9, 2012 at 4:17 AM // reply »
63 Comments

Ctrl+S :-)


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools