United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6260652 : (coll) Arrays.asList(x).toArray().getClass() should be Object[].class

Details
Type:
Bug
Submit Date:
2005-04-25
Status:
Resolved
Updated Date:
2015-08-20
Project Name:
JDK
Resolved Date:
2015-07-09
Component:
core-libs
OS:
linux,windows_xp
Sub-Component:
java.util:collections
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0,6
Fixed Versions:

Related Reports
Duplicate:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Linux itppc27 2.4.19-4GB #1 Mon Aug 4 23:38:42 UTC 2003 i686 unknown

A DESCRIPTION OF THE PROBLEM :
The Collection documentation claims that

    collection.toArray()

is "identical in function" to

    collection.toArray(new Object[0]);

However, the implementation of Arrays.asList does not follow this: If created with an array of a subtype (e.g. String[]), its toArray() will return an array of the same type (because it use clone()) instead of an Object[].

If one later tries to store non-Strings (or whatever) in that array, an ArrayStoreException is thrown.

Either the Arrays.asList() implementation (which may return an array of component type not Object) or the Collection toArray documentation (which does not allow argumentless toArray() to return arrays of subtypes of Object) is wrong.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute code.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[Ljava.lang.Object;@10b62c9
[Ljava.lang.Object;@82ba41

ACTUAL -
[Ljava.lang.String;@10b62c9
[Ljava.lang.Object;@82ba41


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.*;


public class ToArray
{
    public static void main(String[] args)
    {
        List l = Arrays.asList(args);

        System.out.println(l.toArray());
        System.out.println(l.toArray(new Object[0]));
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Only use toArray(Object[]).
###@###.### 2005-04-25 12:45:46 GMT

                                    

Comments
Our backport of this change to jdk8 caused 5 test failures in our (very large) test suite, all due to test (i.e. non-production) code doing dumb things like

List x = ... .asList("a", "b", "c");
String[] y = x.toArray();

where redeclaring as Object[] would have been fine, but more generally, calling toArray at all is almost always a sign that the test code could have been written much simpler, by either using the List or the original input array.
                                     
2015-08-13
@Martin, if everything happens to work, please leave that as a positive affirmation in a comment! Thanks.
                                     
2015-07-20
A backport of this to jdk8 has been committed as a local change at Google, so there will be lots of compatibility testing before jdk9 is released.
                                     
2015-07-20
Core libs review thread:
http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-June/034355.html
                                     
2015-07-16
URL:   http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/fb84b4a830f9
User:  lana
Date:  2015-07-15 22:04:15 +0000

                                     
2015-07-15
URL:   http://hg.openjdk.java.net/jdk9/dev/jdk/rev/fb84b4a830f9
User:  martin
Date:  2015-07-09 17:38:20 +0000

                                     
2015-07-09
10 years later, I still believe this is "just" a bug that should be fixed.
                                     
2015-06-26
This is a long standing issue and what I can tell, there haven't been too many reports of it. I don't see any strong reason to try to squeeze this into jdk8 so deferring it to early jdk9 seems reasonable (to me).
                                     
2013-09-28
A testing datapoint, the current jtreg jdk_core regression suite runs successfully when the toArray method is changed to:

return Arrays.copyOf(a, 0, a.length, Object.class);

This is by no means exhaustive but perhaps a useful indication that this change might be safe.

Nonetheless, any objections to deferring this from 8?
                                     
2013-09-27
EVALUATION

The submitter is correct.
toArray() must always return an object of precise type Object[].
                                     
2005-08-07
SUGGESTED FIX

--- /u/martin/ws/mustang/src/share/classes/java/util/Arrays.java	2005-08-11 11:04:21.718074000 -0700
+++ /u/martin/ws/toArray/src/share/classes/java/util/Arrays.java	2005-08-27 18:01:03.522592000 -0700
@@ -2949,7 +2948,7 @@
 	implements RandomAccess, java.io.Serializable
     {
         private static final long serialVersionUID = -2764017481108945198L;
-	private Object[] a;
+	private final E[] a;
 
 	ArrayList(E[] array) {
             if (array==null)
@@ -2962,17 +2961,27 @@
 	}
 
 	public Object[] toArray() {
-	    return (Object[])a.clone();
+	    return Arrays.copyOf(a, a.length, Object[].class);
+	}
+
+	public <T> T[] toArray(T[] a) {
+	    int size = size();
+	    if (a.length < size)
+		return Arrays.copyOf(this.a, size, (Class<T[]>) a.getClass());
+	    System.arraycopy(this.a, 0, a, 0, size);
+	    if (a.length > size)
+		a[size] = null;
+	    return a;
 	}
 
 	public E get(int index) {
-	    return (E)a[index];
+	    return a[index];
 	}
 
 	public E set(int index, E element) {
-	    Object oldValue = a[index];
+	    E oldValue = a[index];
 	    a[index] = element;
-	    return (E)oldValue;
+	    return oldValue;
 	}
 
         public int indexOf(Object o) {
                                     
2005-08-07



Hardware and Software, Engineered to Work Together