Using java.util.Collections.shuffle

195 views
Skip to first unread message

Andrew

unread,
Apr 6, 2011, 7:45:44 AM4/6/11
to Railo
Hi,

I'm trying to bring some code from Adobe CF over to railo. In the
code I do an array shuffle. When I brought it to railo it's behaving
differently to Adobe CF. In Adobe CF the array after the shuffle
always returns the same three elements, but in Railo I sometimes get
duplicates, eg:

Before shuffle - ['15789','15787','15786']
After shuffle - ['15789','15786','15786']

(15786 is repeated, and 15787 is no longer in the array)

Here's some sample code that'll reproduce it:

===================

<cfset arrTest = ArrayNew(1)>

<cfset arrTest[1] = 15789>
<cfset arrTest[2] = 15787>
<cfset arrTest[3] = 15786>

<cfdump var="#arrTest#">


<!--- Shuffle --->
<cfset CreateObject(
"java",
"java.util.Collections"
).Shuffle(
arrTest
) />

<cfdump var="#arrTest#">

===================

Any ideas? I'm happy to use an alternative means of shuffling if
needs be.

Andrew.

Andrew

unread,
Apr 6, 2011, 8:16:18 AM4/6/11
to Railo
Looks like this has been discussed in the comments on Ben Nadel's blog
also:

http://www.bennadel.com/blog/280-Randomly-Sort-A-ColdFusion-Array-Updated-Thanks-Mark-Mandel.htm

There seems to be a bit of discussion here about differing array
behaviour in Railo (pass by reference versus pass by value). I am not
sure if that's related or not?

Robert Zehnder

unread,
Apr 6, 2011, 10:08:55 AM4/6/11
to ra...@googlegroups.com
Are both Railo and your ACF box running the same version of the JRE?  Since you are dealing with native Java objects I wouldn't think the server implementation would affect it (but I have been wrong before).

I quickly tried your example this morning on my local dev machine and I did not get duplicates in the array, but I couldn't get the sort (I was running through it quickly as I only had a few minutes to look at it).  Passing by reference should not make a difference but you could always duplicate() your array before passing it in.

Robert Zehnder

unread,
Apr 6, 2011, 10:20:28 AM4/6/11
to ra...@googlegroups.com
I just checked it out again and it looks like it is working on my test environment: Railo Express  3.3.0.006 beta with 1.6.0_01 (Sun Microsystems Inc.)

Code:

<cfscript>
 arrayToSort = [12301,12302,12303,12304,12305];

 createObject("java", "java.util.Collections").Shuffle(arrayToSort);
 writeDump(arrayToSort);
</cfscript>


Michael Offner

unread,
Apr 6, 2011, 10:23:23 AM4/6/11
to ra...@googlegroups.com
has nothing to do with "pass-by-***".
we have already solved the problem

Problem was the implementation of the method java.util.List#set(int, java.lang.Object), this method is never used by Railo, but supported because we have implemented the List interface for ArrayImpl and of course the shuffle method use this method. the return value of this function should be the element previously at the specified position, but railo has returned the object set to the array, like every set action in Railo does.

/micha






2011/4/6 Andrew <am2...@gmail.com>

Michael Offner

unread,
Apr 6, 2011, 10:27:19 AM4/6/11
to ra...@googlegroups.com
it is working in this case, because the shuffle method use a other algoritm when there are less than 5 objects in the Array (List), see (bold) code below.

/micha


    private static final int SHUFFLE_THRESHOLD        =    5;

...

    public static void shuffle(List<?> list, Random rnd) {

        int size = list.size();

        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {

            for (int i=size; i>1; i--)

                swap(list, i-1, rnd.nextInt(i));

        } else {

            Object arr[] = list.toArray();


            // Shuffle array

            for (int i=size; i>1; i--)

                swap(arr, i-1, rnd.nextInt(i));


            // Dump array back into list

            ListIterator it = list.listIterator();

            for (int i=0; i<arr.length; i++) {

                it.next();

                it.set(arr[i]);

            }

        }

    }




2011/4/6 Robert Zehnder <rob...@kisdigital.com>

Andrew Myers

unread,
Apr 6, 2011, 5:35:34 PM4/6/11
to ra...@googlegroups.com
Thank you Michael.  I'll see if I can build the latest and test later today.

I should be able to patch the latest production build with this change, right?

Andrew

Sent from my mobile

Todd Rafferty

unread,
Apr 6, 2011, 5:59:16 PM4/6/11
to ra...@googlegroups.com
You'd have to upgrade your production to 3.2.2.0xx+ to get this patch.
--
~Todd Rafferty
Volunteer
Community Manager
Railo Server - Open Source
----

Andrew Myers

unread,
Apr 7, 2011, 1:42:13 AM4/7/11
to ra...@googlegroups.com
Hi Guys,

I've checked out the code for 3.2.2.000 from github and tried to build
it in eclipse but I'm running into an error as per below.

I'm using jdk 1.5.0_22 on Windows 7 (32-bit). My "compile server" is
running on Java 6 - not sure if that is a potential issue.

Has anyone come across this before and can help me please?

Regards,
Andrew

Buildfile: C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-master\build.xml
init:
[echo] ***** Start Railo build process. *****
clean:
[echo] Deleting build and dist
getInfo:
[echo] Extracting version information from file src/railo/runtime/Info.ini
[echo] Version is: 3.2.2.000.1.rc
clean:
[echo] Deleting build and dist
clean:
[echo] Deleting build and dist
[delete] Deleting directory
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo\build
master:
[echo] ***** Building railo-loader.jar *****
clean:
[echo] Deleting build and dist
init:
[echo] Creating the build and dist directories.
[mkdir] Created dir:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-loader\build\classes
[mkdir] Created dir:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-loader\dist
compile:
[echo] Compile the RailoLoader src.
[javac] Compiling 192 source files to
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-loader\build\classes
[javac] Note: Some input files use or override a deprecated API.
[javac] Note: Recompile with -Xlint:deprecation for details.
[javac] Note: Some input files use unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
package:
[echo] Packaging the railo-loader.jar file.
[jar] Building jar:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-loader\dist\railo-loader.jar
install:
[echo] Copy the railo-loader.jar to the Railo core lib directory.
[copy] Copying 1 file to
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\libs
[echo] ***** Building Railo core.rc *****
getInfo:
[echo] Extracting version information from file src/railo/runtime/Info.ini
[echo] Version is: 3.2.2.000.1.rc
clean:
[echo] Deleting build and dist
init:
[echo] Creating the build, admin and dist directories.
[mkdir] Created dir:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\build\classes
[mkdir] Created dir:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\build\admin
[mkdir] Created dir:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\dist
compile:
[echo] Compile Railo src.
[javac] Compiling 2149 source files to
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\build\classes
[javac] C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\src\railo\runtime\ComponentImpl.java:234:
reference to ComponentScopeShadow is ambiguous, both method
ComponentScopeShadow(railo.runtime.ComponentImpl,java.util.Map<railo.runtime.type.Collection.Key,java.lang.Object>)
in railo.runtime.ComponentScopeShadow and method
ComponentScopeShadow(railo.runtime.ComponentImpl,railo.runtime.ComponentScopeShadow)
in railo.runtime.ComponentScopeShadow match
[javac] if(useShadow) trg.scope=new
ComponentScopeShadow(trg,(ComponentScopeShadow)trg.base.scope);
[javac] ^
[javac] C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\src\railo\runtime\ComponentImpl.java:398:
reference to ComponentScopeShadow is ambiguous, both method
ComponentScopeShadow(railo.runtime.ComponentImpl,java.util.Map<railo.runtime.type.Collection.Key,java.lang.Object>)
in railo.runtime.ComponentScopeShadow and method
ComponentScopeShadow(railo.runtime.ComponentImpl,railo.runtime.ComponentScopeShadow)
in railo.runtime.ComponentScopeShadow match
[javac] else scope=new
ComponentScopeShadow(this,(ComponentScopeShadow)base.scope);
[javac] ^
[javac] C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\src\railo\runtime\reflection\Invoker.java:308:
warning: non-varargs call of varargs method with inexact argument type
for last parameter;
[javac] cast to java.lang.Object for a varargs call
[javac] cast to java.lang.Object[] for a non-varargs call and to
suppress this warning
[javac] return m.invoke(o,null);
[javac] ^
[javac] Note: Some input files use or override a deprecated API.
[javac] Note: Recompile with -Xlint:deprecation for details.
[javac] Note: Some input files use unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.
[javac] 2 errors
[javac] 1 warning

BUILD FAILED
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-master\build.xml:25:
The following error occurred while executing this line:
C:\Users\andrew\projects\am2605-railo-b57682a\railo-java\railo-core\build.xml:57:
Compile failed; see the compiler error output for details.

Total time: 32 seconds

denstar

unread,
Apr 7, 2011, 4:19:36 AM4/7/11
to ra...@googlegroups.com
If you want to build from github, the easiest is probably to use this project:

https://github.com/denuno/railo-build

As it comes with git (jgit) and will detect java 1.5 if you installed
it to the default location (It also has an easy way to set the
location in build/build.xml).

INSTRUCTIONS FOR USE:

Select the "download" link, save it as a zip, and then expand it somewhere.

Double click the "build-railo.bat" file, select option 1, and wait for
a [long] bit as it downloads all the sources.

Wait a bit more for it to compile them (theoretically).

When it's done, you should have a 3.2.2.002.rc file in the ./dist directory.

Apply this change:
https://github.com/getrailo/railo/commit/c5e7281136f227bf9bee3e1dec11df66172f1a23

Edit the build file (build/build.xml) to set the build number to 3.2.2.003

Run railo-build.bat again. Select option 1. (It should be a lot
faster this time since it won't have to DL the sources. If you don't
have compile errors, you can select option 2, and it will fire up the
freshly built version for testing)

Assuming you didn't run into any errors, you then drop the new .rc
file from ./dist into the railo patches dir
(WEB-INF/lib/railo/context/patches IIRC) and restart railo.

And I think that's it. Let us know how you get on, por favor!

:Den

--
Knowledge is recognition of something absent; it is a salutation, not
an embrace.
George Santayana

Andrew

unread,
Apr 7, 2011, 7:21:36 AM4/7/11
to Railo
Hey Denny,

Now I understand the issue I actually came up with another solution,
which was to convert to a java.util.ArrayList, shuffle that, and then
convert back to a cf Array. Something like this:

<cffunction name="arrayShuffle" returntype="array">
<cfargument name="arrayIn" type="array">

<!--- NB: Only designed to work with single dimensioned arrays
--->

<cfset var jArrayList = CreateObject("java",
'java.util.ArrayList').init(arguments.arrayIn)>
<cfset var cfArray = ArrayNew(1)>
<cfset var objIterator = "">

<!--- Shuffle jArrayList --->
<cfset CreateObject(
"java",
"java.util.Collections"
).Shuffle(
jArrayList
) />

<!--- Now convert it back to a ColdFusion Array --->
<cfset objIterator = jArrayList.iterator()>
<cfloop condition="objIterator.hasNext()">
<cfset ArrayAppend(cfArray, objIterator.next())>
</cfloop>

<cfreturn cfArray>

</cffunction>

But I'm checking your thing out anyway - it's running now. Will let
you know how I get along. :-)


On Apr 7, 6:19 pm, denstar <valliants...@gmail.com> wrote:
> If you want to build from github, the easiest is probably to use this project:
>
> https://github.com/denuno/railo-build
>
> As it comes with git (jgit) and will detect java 1.5 if you installed
> it to the default location (It also has an easy way to set the
> location in build/build.xml).
>
> INSTRUCTIONS FOR USE:
>
> Select the "download" link, save it as a zip, and then expand it somewhere.
>
> Double click the "build-railo.bat" file, select option 1, and wait for
> a [long] bit as it downloads all the sources.
>
> Wait a bit more for it to compile them (theoretically).
>
> When it's done, you should have a 3.2.2.002.rc file in the ./dist directory.
>
> Apply this change:https://github.com/getrailo/railo/commit/c5e7281136f227bf9bee3e1dec11...
Reply all
Reply to author
Forward
0 new messages