Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at the New York ColdFusion User Group (May. 2008) with:

Creating Typed Java Arrays In ColdFusion Using JavaCast()

By Ben Nadel on
Tags: ColdFusion

A few years ago, I created a user defined ColdFusion function - toJava() - that tried to me "smart" about the way it cast ColdFusion values into Java values. Unfortunately, it turns out that I was basically re-creating a feature that ColdFusion already had; only, I didn't really understand how it worked. I'm talking about the javaCast() function. And, more specifically, I'm talking about creating typed Java arrays using javaCast(). At the time, I didn't understand how array-casting worked. Now, years later, I think I finally get it.

I believe that the root of my misunderstanding of the javaCast() function stemmed from the fact that I wasn't thinking properly about simple data types vs. complex data types. Or, perhaps more accurately, native data types vs. class instances. When you're dealing with native data types like Booleans, Strings, and Integers, javaCast() is a lot more flexible - you just pass it an array of ColdFusion values and javaCast() will cast it properly. If you're dealing with class instances, however, javaCast() can only perform the array cast, not the individual value casts.

To demonstrate below, I'm creating typed Java arrays using both native data types and Java class instances. With the native data types, I'm showing both the simple cast (ie, the collection-only) as well as the [unnecessarily] comprehensive cast (ie, I'm casting each value individually). With the class instances, I can't use a simple cast - I have to explicitly cast each value in the ColdFusion array before I cast the entire collection.

  • <cfscript>
  •  
  • // Byte arrays. Binary data is represented by an array of bytes.
  • // And, each byte is represented by an integer. For simple values,
  • // we don't have to manually cast each value - we can just pass-in
  • // the array and ColdFusion will perform the cast.
  •  
  • // Test 1 - Spell "SARAH" with ColdFusion numbers.
  •  
  • bytes = javaCast(
  • "byte[]",
  • [ 83, 65, 82, 65, 72 ]
  • );
  •  
  • writeOutput( charsetEncode( bytes, "utf-8" ) & "<br />" );
  •  
  • // Test 2 - Spell "SARAH" with Java bytes.
  •  
  • bytes = javaCast(
  • "byte[]",
  • [
  • javaCast( "byte", 83 ),
  • javaCast( "byte", 65 ),
  • javaCast( "byte", 82 ),
  • javaCast( "byte", 65 ),
  • javaCast( "byte", 72 )
  • ]
  • );
  •  
  • writeOutput( charsetEncode( bytes, "utf-8" ) & "<br />" );
  •  
  •  
  • // ------------------------------------------------------ //
  • // ------------------------------------------------------ //
  •  
  •  
  • // Char arrays. Character arrays work the same way that byte
  • // arrays work: you don't have to perform the cast manually
  • // for each character - ColdFusion will do that for you. To
  • // test this, we'll use a StringBuffer which can accept char[]
  • // as an append() argument.
  •  
  • buffer = createObject( "java", "java.lang.StringBuffer" ).init();
  •  
  • // Test 1 - Add "TRICIA" with ColdFusion strings.
  •  
  • buffer.append(
  • javaCast( "char[]", [ "T", "R", "I", "C", "I", "A" ] )
  • );
  •  
  • // Test 2 - Add "TRICIA" with Java chars.
  •  
  • buffer.append(
  • javaCast(
  • "char[]",
  • [
  • javaCast( "char", "T" ),
  • javaCast( "char", "R" ),
  • javaCast( "char", "I" ),
  • javaCast( "char", "C" ),
  • javaCast( "char", "I" ),
  • javaCast( "char", "A" )
  • ]
  • )
  • );
  •  
  • // Since we appended twice, should output "TRICIATRICIA".
  • writeOutput( buffer.toString() & "<br />" );
  •  
  •  
  • // ------------------------------------------------------ //
  • // ------------------------------------------------------ //
  •  
  •  
  • // String arrays. Although a slightly more complex data type,
  • // strings work the same way that bytes and chars work. You don't
  • // have to cast the individual values manually. To test this, we'll
  • // use the common string utils which can accepts String[] as an
  • // argument in some methods.
  •  
  • utils = createObject( "java", "org.apache.commons.lang.StringUtils" );
  •  
  • // Test 1 - Use ColdFusion strings.
  •  
  • inputs = javaCast(
  • "string[]",
  • [
  • "Hello world",
  • "Hello there!",
  • "Hell yis!"
  • ]
  • );
  •  
  • writeOutput( utils.getCommonPrefix( inputs ) & "<br />" );
  •  
  • // Test 2 - Use Java strings (which are really the same thing).
  •  
  • inputs = javaCast(
  • "string[]",
  • [
  • javaCast( "string", "Hello world" ),
  • javaCast( "string", "Hello cutie pie!" ),
  • javaCast( "string", "Hell yis!" )
  • ]
  • );
  •  
  • writeOutput( utils.getCommonPrefix( inputs ) & "<br />" );
  •  
  •  
  • // ------------------------------------------------------ //
  • // ------------------------------------------------------ //
  •  
  •  
  • // With simple values like integer, char, string, float, long,
  • // etc., ColdFusion will create a types array and ensure that
  • // each item within that array is properly casted. With complex
  • // Java Class instances, things are a little less flexible. If
  • // you need a typed array of some set of class instances, you
  • // have to make sure that each item is *alread* in the proper
  • // data type.
  •  
  • // In ColdFusion, a common example of this is the need to create
  • // a collection of URL[] instances for a Java class loader. First,
  • // we have to create a ColdFusion array that is populated with
  • // actual Java URL instances:
  • urls = [
  • createObject( "java", "java.net.URL" ).init(
  • javaCast( "string", "file:///foo" )
  • ),
  • createObject( "java", "java.net.URL" ).init(
  • javaCast( "string", "file:///bar" )
  • )
  • ];
  •  
  • // Once we have the ColdFusion array populated with URL instances,
  • // we can then cast the ColdFusion array to a typed Java array in
  • // order to instantiate the class loader.
  • loader = createObject( "java", "java.net.URLClassLoader" ).init(
  • javaCast( "java.net.URL[]", urls )
  • );
  •  
  • </cfscript>

The fact that ColdFusion lives on top of Java means that we have a world of powerful features laying just below the surface. Unfortunately, communication with the Java layer requires type-casting; but, luckily, ColdFusion's javaCast() function makes that a fairly easy task, once you understand how it works.




Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.