Skip to main content

Dynamically Invoking Method Names On a Java Object From CFML

A co-worker contacted me today asking how he might go about solving what turned out to be a rather interesting issue.

From a CFML application (running on Open BlueDragon) he's calling a .NET web service and getting an array of objects back. By the time all the SOAP magic happens the objects in the array on the CFML side are Java objects.

What he wanted to do next was loop over this array of Java objects and, for each object in the array, call every getXXX() method contained in the object. But the application is getting numerous different types of objects back, some of which have a large number of get methods in them, and he didn't want to have to hard-code a method call for each one. In addition, the get methods may change from time to time and while we're supposed to be notified when changes occur, we didn't want to rely on that.

So consider the following pseudocode:

<cfinvoke webservice="url to webservice"
    returnvariable="myJavaObjects" />

So at this point the variable myJavaObjects is an array of homogeneous Java objects.

Next, we want to loop over that array and for each Java object, call all of its get methods.

My first thought was that this is one of those rare cases where Evaluate() might be justified. But I also thought there had to be a better way, so perhaps against my co-worker's will we spent about an hour hammering through some experiments. I'll spare you the various things we tried and cut to the chase of the final solution.

One thing I learned while working through this is that CFINVOKE works on Java objects. Who knew? OK, maybe you knew, but I hadn't ever had cause to try it before so I didn't know.

So step one is once we get the array of Java objects back from the web service, since we know they're homogeneous objects, we'll just use some Java reflection magic on the first one to create an array of the method names beginning with get:

<!--- this returns an array of java.lang.reflect.Method objects --->
<cfset methods = myJavaObjects[1].getClass().getMethods() />
<!--- now we'll create an array of method names starting with get --->
<cfset methodNames = [] />
<cfloop array="#methods#" index="method">
    <cfif Left(method.getName(), 3) == "get">
        <cfset ArrayAppend(methodNames, method.getName()) />

So now we have an array of strings that are the method names from the Java object that start with get. In the actual application we're actually omitting some of the methods starting with get because they're not relevant (e.g. getClass(), getSerializer(), etc.) so I'm just keeping it simple for the purposes of illustration.

The next step is to loop over the array of Java objects, and on each loop iteration, call each get method and for demo purposes simply output the results. Here's where we use CFINVOKE to call methods dynamically on the Java objects:

<cfloop array="#myJavaObjects#" index="javaObject">
    <cfloop array="#methodNames#" index="methodName">
        <cfinvoke component="#javaObject#" method="#methodName#" returnvariable="foo" />
        <cfoutput>#foo#<br /></cfoutput>

And with that, we're getting an array of Java objects back from a .NET web service (with the .NET object to Java object translation being handled transparently by the web service engine of course), we're using a bit of Java reflection to get a list of the getters from the Java object, and we're then looping over the array of Java objects and calling the get methods on each Java object.

As an aside, during experimentation we went down the path of using Java reflection directly, but that got pretty messy and didn't seem to offer any benefit over doing things at a higher level in CFML. Interestingly, while we were messing with some things we had an error generated from CFINVOKE reminding me that under the hood, CFINVOKE is doing all the Java reflection nastiness for you.

Not sure how handy a tip that will be for others but I wanted to blog it while it was still fresh in my mind. There's probably several other ways to solve this problem so if others have approached this differently I'd love to hear about it.


Popular posts from this blog

Installing and Configuring NextPVR as a Replacement for Windows Media Center

If you follow me on Google+ you'll know I had a recent rant about Windows Media Center, which after running fine for about a year suddenly decided as of January 29 it was done downloading the program guide and by extension was therefore done recording any TV shows.

I'll spare you more ranting and simply say that none of the suggestions I got (which I appreciate!) worked, and rather than spending more time figuring out why, I decided to try something different.

NextPVR is an awesome free (as in beer, not as in freedom unfortunately ...) PVR application for Windows that with a little bit of tweaking handily replaced Windows Media Center. It can even download guide data, which is apparently something WMC no longer feels like doing.

Background I wound up going down this road in a rather circuitous way. My initial goal for the weekend project was to get Raspbmc running on one of my Raspberry Pis. The latest version of XBMC has PVR functionality so I was anxious to try that out as a …

Running a Django Application on Windows Server 2012 with IIS

This is a first for me since under normal circumstances we run all our Django applications on Linux with Nginx, but we're in the process of developing an application for another department and due to the requirements around this project, we'll be handing the code off to them to deploy. They don't have any experience with Linux or web servers other than IIS, so I recently took up the challenge of figuring out how to run Django applications on Windows Server 2012 with IIS.

Based on the dated or complete lack of information around this I'm assuming it's not something that's very common in the wild, so I thought I'd share what I came up with in case others need to do this.

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Assumptions and CaveatsThe operating system is Windows Server 2012 R2, 64-bit. If another variant of the operating system is being used, these instructions may not work properly.All of the soft…

Fixing DPI Scaling Issues in Skype for Business on Windows 10

My setup for my day job these days is a Surface Pro 4 and either an LG 34UC87M-B or a Dell P2715Q monitor, depending on where I'm working. This is a fantastic setup, but some applications have trouble dealing with the high pixel density and don't scale appropriately.
One case in point is Skype for Business. For some reason it scales correctly as I move between the Surface screen and the external monitor when I use the Dell, but on the LG monitor Skype is either massive on the external monitor, or tiny on the Surface screen.
After a big of digging around I came across a solution that worked for me, which is to change a setting in Skype's manifest file (who knew there was one?). On my machine the file is here: C:\Program Files\Microsoft Office\Office16\LYNC.EXE.MANIFEST
And the setting in question is this:
Which I changed to this: <dpiAware>False/PM</dpiAware>
Note that you'll probably have to edit the file as administr…