The ColdFusion 10 invoke() Function Works With Most Java Objects
The other day, when I was working on my light-weight ColdFusion wrapper for the OWASP (Open Web Application Security Project) Java Encoder project, I had to dynamically invoke methods on the underlying Java object. In the past, I've had to use the evaluate() function to dynamically invoke Java methods. But, as of ColdFusion 10, the new invoke() function has support for most Java objects.
I say "most" Java objects because invoke() won't actually work on "java.lang.String" instances. If you pass a Java String to the invoke() function, ColdFusion thinks that you are providing the name of a ColdFusion component that you want to instantiate. So, for example, if you try to execute:
<cfscript>
input = javaCast( "string", "Good morning Tricia." );
result = invoke( input, "toUpperCase", [] );
writeOutput( result );
</cfscript>
... you'll get the following ColdFusion error:
Could not find the ColdFusion component or interface Good morning Tricia . Ensure that the name is correct and that the component or interface exists.
That's a little bit of a bummer. But, fortunately, invoke() works with any non-String Java object where the invoke() signature is disambiguated. To see this in action, we can create an instance of the java.util.ArrayList class and then dynamically invoke the .add() method:
<cfscript>
collection = createObject( "java", "java.util.ArrayList" ).init();
// CAUTION: Using invoke() here is not strictly necessary; I'm just using
// it for demonstration purposes of the functionality.
invoke( collection, "add", [ "Happy" ] );
invoke( collection, "add", [ "New" ] );
invoke( collection, "add", [ "Year" ] );
invoke( collection, "add", [ "&" ] );
invoke( collection, "add", [ "Best" ] );
invoke( collection, "add", [ "Wishes!" ] );
writeOutput( arrayToList( collection, " " ) );
</cfscript>
When we run this code, we get the following output:
Happy New Year & Best Wishes!
Now, you don't really need invoke() in this particular circumstance; nothing is actually "dynamic". But, both the method name and the method arguments can be dynamic which is great because ColdFusion's "argumentCollection" functionality doesn't actually work Java methods. For example, if you wanted to try to run this code:
<cfscript>
collection = createObject( "java", "java.util.ArrayList" ).init();
collection.add( argumentCollection = [ "Hello world" ] );
</cfscript>
... you'll get the following ColdFusion error:
Cannot invoke method add on an object of type java.util.ArrayList with named arguments. Use ordered arguments instead.
However, we can easily pass in a dynamic argument collection to a Java method using invoke():
<cfscript>
collection = createObject( "java", "java.util.ArrayList" ).init();
methodName = "add";
methodArguments = [ "Hello World" ];
invoke( collection, methodName, methodArguments );
</cfscript>
Which works exactly as we'd hope!
Using invoke() with Java is not functionality that you need a whole lot. But, it can be really helpful in certain cases, like creating proxies to Java objects.
Want to use code from this post? Check out the license.
Reader Comments
hah, that's actually pretty cool
@Rob,
invoke() is my new favorite method :) You don't need it all that often, but it just works good.