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:

Converting A Java Array To A ColdFusion Array

By Ben Nadel on
Tags: ColdFusion

A while back, I discovered that splitting a string into an array using the Java String::Split() method produced what appeared to be a ColdFusion array, but what was, in fact, a read-only Java array (at least from the ColdFusion perspective). Under the hood, ColdFusion arrays are really collection objects, not true arrays. Because of this, ColdFusion does not inherently resize or set values into Java arrays.

I have always knowm that to get around this, you could create a ColdFusion array, then loop over the Java array and copy the values:

  • <!---
  • Create a string and then split it into an array using
  • the String::Split() method. This will give us an array,
  • but NOT a traditional ColdFusion array. This is a read-
  • only array (well, from CF's perspective).
  • --->
  • <cfset arrGirls = ToString(
  • "Maria Bello,Christina Cox,Meg Ryan"
  • ).Split( "," )
  • />
  •  
  • <!--- Create a ColdFuion array. --->
  • <cfset arrCFGirls = ArrayNew( 1 ) />
  •  
  • <!--- Loop over array to copy values. --->
  • <cfloop
  • index="intGirl"
  • from="1"
  • to="#ArrayLen( arrGirls )#"
  • step="1">
  •  
  • <!--- Copy value. --->
  • <cfset arrCFGirls[ intGirl ] = arrGirls[ intGirl ] />
  •  
  • </cfloop>

But this always seems like such a ganky way of doing it. I had hoped there was a more elegant solution, but never really look the time to look it up. Well, finally motivated by Rob Marchetti's comment on my previous post on the subject matter, I figured I would finally look into it.

Just to recap, when you split a string using the String::Split() method, you get what looks like an array:

  • <!---
  • Create a string and then split it into an array using
  • the String::Split() method. This will give us an array,
  • but NOT a traditional ColdFusion array. This is a read-
  • only array (well, from CF's perspective).
  • --->
  • <cfset arrGirls = ToString(
  • "Maria Bello,Christina Cox,Meg Ryan"
  • ).Split( "," )
  • />
  •  
  • <!---
  • Dump out the array. You will see that it looks like a
  • standard ColdFusion array (but it is not).
  • --->
  • <cfdump
  • var="#arrGirls#"
  • label="Array via Split()"
  • />

When we CFDump that out, we get:


 
 
 

 
Java Array To ColdFusion Array  
 
 
 

Looks good, right? Sure, but then, when we try to go and alter it, as we could any other ColdFusion array:

  • <!--- Try to add a girl to this array. --->
  • <cfset ArrayAppend(
  • arrGirls,
  • "Madonna"
  • ) />

... we get the following ColdFusion error:

The Coldfusion function [ArrayAppend] is not supported on this object. The Coldfusion function [ArrayAppend] is not supported on an object of type [coldfusion.runtime.Cast$1]. <br>For Example: XML objects can be operated on by a subset of the Struct and Array functions but not all.

So our goal now becomes to convert this string array into a ColdFusion collection "array." As it turns out, this can be done in a two part process - converting the array into a list, which supports the Java Collection interface, and then add that list to an existing ColdFusion array.

Let's take a look at how to convert the Java array into a List. Using the Java Array utility class, we can use ColdFusion to manipulate Java arrays. In this case, we are going to use the AsList() method to convert the Java array to a List object:

  • <!---
  • Using the Java array, we can use the Array utility
  • class to convert this array to a fixed size list.
  • --->
  • <cfset arrGirlList = CreateObject(
  • "java",
  • "java.util.Arrays"
  • ).AsList(
  • arrGirls
  • ) />
  •  
  • <!---
  • Dump out the list object. You will see that it looks
  • like a standard ColdFusion array (but it is not).
  • --->
  • <cfdump
  • var="#arrGirlList#"
  • label="Array via AsList()"
  • />

When we CFDump that List object out, we get:


 
 
 

 
Java Array To ColdFusion Array  
 
 
 

Be careful! Again, this object looks like a ColdFusion array, but it is not. If we tried to modify it:

  • <!--- Try to add a girl to this list. --->
  • <cfset ArrayAppend(
  • arrGirlList,
  • "Frances McDormand"
  • ) />

... we get the following ColdFusion error:

The Coldfusion function [ArrayAppend] is not supported on this object. The Coldfusion function [ArrayAppend] is not supported on an object of type [java.util.Arrays$ArrayList]. <br>For Example: XML objects can be operated on by a subset of the Struct and Array functions but not all.

Don't worry, we are almost there. The List object that we have now created supports the Java Collection interface. If you have messed around with any of the underlying Java method of ColdFusion objects, you might know that the ColdFusion Array (collection) has a method called AddAll(). AddAll() takes a Collection-interfaced object and adds all of its items to the ColdFusion array:

  • <!--- Create an empty ColdFusion array. --->
  • <cfset arrGirls = ArrayNew( 1 ) />
  •  
  • <!---
  • Add all the elements of the list to the new
  • ColdFusion array. Since the List impliments the
  • Collections interface, this will work quite nicely.
  • --->
  • <cfset arrGirls.AddAll(
  • arrGirlList
  • ) />
  •  
  • <!--- Add a new girl to the array. --->
  • <cfset ArrayAppend(
  • arrGirls,
  • "Madonna"
  • ) />
  •  
  • <!--- Dump out the true ColdFusion array. --->
  • <cfdump
  • var="#arrGirls#"
  • label="Array via AddAll( LIST )"
  • />

When we run the above code, we get no ColdFusion errors and our resultant array looks like this:


 
 
 

 
Java Array To ColdFusion Array  
 
 
 

Ok, so that's a bit of a process with a few steps. However, we can "simplify" and by that I mean condense the code into something that might be considered a little more manageable:

  • <!---
  • To make the code more condense, you could do
  • something like this. Not nearly as readable, but
  • at least you end up with a ColdFusion array.
  • --->
  • <cfset arrGirls = ArrayNew( 1 ) />
  •  
  • <!---
  • Split the girl string into a Java array but store
  • it in the girls array.
  • --->
  • <cfset arrGirls.AddAll(
  • CreateObject(
  • "java",
  • "java.util.Arrays"
  • ).AsList(
  • ToString(
  • "Maria Bello,Christina Cox,Meg Ryan"
  • ).Split( "," )
  • )
  • ) />

That's not the easiest thing to read, but to me, it is still a little more elegant that looping over the array and copying over each item (as we did at the beginning of this post). I think the best solution would be for ColdFusion to update their Array wrapper and allow the AddAll() method to accept an array. But for now, this will work.




Reader Comments

if you use split( ",", -1) this should catch any trailing empty lists at the end... i think... i haven't tested this though. :)

Reply to this Comment

Guys, let's not forget there are many ways to get a Java array. Using the Split() method is just one of them. Many of the Java objects and interfaces have methods that return stuff as arrays. The focus here was on getting those into ColdFusion "array" form... the focus was not meant to be on Split(). That's just happens to be an easy one to use, but I could have just as easily when with String::ToCharArray().

@Andy,

I will do that, I think this is something that could be cool and mostly likely is very easy to implement.

Reply to this Comment

@Rupesh,

Very cool! I think the ability to keep empty list elements is going to make people very happy :)

Reply to this Comment

Ben--

This was a life saver. Again, your blog helps the common programmer solve a problem. I really appreciate it.

Tim

Reply to this Comment

@Ben
I know this is an old post, but I found this while trying to solve this problem:

MyORMArr=ORMExecutequery('Select Name, CustomerAlias from Equipment');

This yield an java array of java arrays and we want to add and/or change some values before feeding this array of array to jquery DataTables.Big problem with NULL values because you can't even check for example Isvalid(MyORMArr[3,2] and java arrays are readonly.

So I did this
serialized=SerializeJson(MyOrmArr);
//NewArr is a CF array now (but still some Null value problems in CF90
NewArr=DeSerializeJSON(serialized);
//some additions to NewArr
...
NewArr[3,2]="somevalue";
//generate JSON from modified array
//because CF DeSerialize is broken in CF9 I have to fix this
//replacing "null" by null in JSON string
NewSerialized=Replace(SerializJson(NewArr),'"null"','null');

I was wondering if I forget something. For us this seems to work, but null value support in CF is horrible.

Reply to this Comment

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.