Weird behaviour with arrays in ColdFusion
Asked Answered
M

2

5

I am facing issue with a piece of code, with slight modification I am getting different results which should not be the case.

Version 1 is giving the correct results, I am facing issue with Version 2 which is the actual code.

Version 1:

<cfset keywords = listToArray("1,2,3,4,5,6,7,8,9,10")>

<!--- Common Code Below --->
<cfoutput>#getMetadata(keywords).getName()#</cfoutput>

<cfset toBeAdded = keywords>
<cfset toBeInactivated = listToArray("1,3,4,6,8")>
<cfset toBeActivated = toBeInactivated>

<cfset toBeAdded.removeAll(toBeInactivated)>
<cfset toBeInactivated.removeAll(keywords)>
<cfset toBeActivated.retainAll(keywords)>

Version 2:

<cfset keywords = []>
<cfloop from="1" to="10" index="counter">
    <cfset arrayAppend( keywords, counter )>
</cfloop>

<!--- If I add following line here then it is working as expected and similar to version 1:  --->
<!--- <cfset keywords = listToArray(arrayToList(keywords))> --->

<!--- Common Code Below --->
<cfoutput>#getMetadata(keywords).getName()#</cfoutput>

<cfset toBeAdded = keywords>
<cfset toBeInactivated = listToArray("1,3,4,6,8")>
<cfset toBeActivated = toBeInactivated>

<cfset toBeAdded.removeAll(toBeInactivated)>
<cfset toBeInactivated.removeAll(keywords)>
<cfset toBeActivated.retainAll(keywords)>

Outputs:

enter image description hereenter image description here

Here are the gists: Version 1 and Version 2.

Any suggestions are greatly appreciated!

Moulin answered 29/6, 2017 at 8:37 Comment(0)
E
6

I'm no Java guy but from what I can tell...

In Version 1: keywords contains java.lang.String values and in Version 2: keywords contains java.lang.Double values.

In Version 2: toBeInactivated contains strings values to be removed from the array of doubles.

Since those Java types do not match, they won't be removed from the collection properly. I'm guessing when CF passes the underlying object data around, it's never casted correctly. Which honestly I'd expect when everything is typeless to CF.

Adding on from the comment by @Twillen below, this works when you cast counter to a type of java.lang.String:

<cfset keywords = []>
<cfloop from="1" to="10" index="counter">
    <cfset arrayAppend( keywords, javaCast("string", counter) )>
</cfloop>


<!--- Common Code Below --->
<cfoutput>#getMetadata(keywords).getName()#</cfoutput>

<cfset toBeAdded = keywords>
<cfset toBeInactivated = listToArray("1,3,4,6,8")>
<cfset toBeActivated = toBeInactivated>

<cfset toBeAdded.removeAll(toBeInactivated)>
<cfset toBeInactivated.removeAll(keywords)>
<cfset toBeActivated.retainAll(keywords)>

<cfdump var="#toBeAdded#" label="To Be Added">
<cfdump var="#toBeInactivated#" label="To Be Inactivated">
<cfdump var="#toBeActivated#" label="To Be Activated">
Emilemile answered 29/6, 2017 at 12:59 Comment(3)
You completed your answer before I completed mine. The only thing I'd add is you can get versin two to match version one by casting the values to string with arrayAppend( keywords, JavaCast("String", counter).Galatea
Ah, that didn't strike me. Thanks :)Moulin
"Which honestly I'd expect when everything is typeless to CF." True, but only with CF methods. Dumping the object shows removeAll() and retainAll() aren't implemented by CF. It's inherited from java's Vector, so no special CF handling. You get whatever rules Vector applies to collections. pastebin.com/8DjrtFEECalley
M
0

A ColdFusion array isn't a Java Collection object. So I question the use of removeAll() and retainAll() with such arrays. Bearing that in mind, my answer is:

<cfset keywords = createobject("java","java.util.Vector").init()>
<cfset toBeAdded = createobject("java","java.util.Vector").init()>
<cfloop from="1" to="10" index="counter">
    <cfset keywords.add(javaCast("int", counter))>
    <cfset toBeAdded.add(javaCast("int", counter))>
</cfloop>

<!--- Common Code Below --->
<cfoutput>#getMetadata(keywords).getName()#</cfoutput>

<cfset listToBeInactivated = "1,3,4,6,8">
<cfset toBeInactivated = createobject("java","java.util.Vector").init()>
<cfset toBeActivated = createobject("java","java.util.Vector").init()>
<cfloop list="#listToBeInactivated#" index="index">
    <cfset toBeInactivated.add(javaCast("int", index))>
    <cfset toBeActivated.add(javaCast("int", index))>
</cfloop>

<cfset toBeAdded.removeAll(toBeInactivated)>
<cfset toBeInactivated.removeAll(keywords)>
<cfset toBeActivated.retainAll(keywords)>

<cfdump var="#toBeAdded#" label="toBeAdded">
<cfdump var="#toBeInactivated#" label="toBeInactivated">
<cfdump var="#toBeActivated#" label="toBeActivated">
Muttonhead answered 6/7, 2017 at 14:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.