JDK-6432565 : ClassCastException in SwingWorker
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2006-05-31
  • Updated: 2017-05-16
  • Resolved: 2006-07-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b92Fixed
Description
FULL PRODUCT VERSION :
java version "1.6.0-beta2"
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b85)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b85, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Linux localhost.localdomain 2.6.15-1.1833_FC4 #1 Wed Mar 1 23:41:37 EST 2006 i686 i686 i386 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
The EDT (Event dispatch Thread) raises a ClassCastException
with the code below.

Data published by doInBackground() are stored in a list
and then converted in an array and send to method process()
in order to reduce synchronization time between EDT and worker thread.

The problem is to determine the class of the array passed to the process()
method at runtime. Because generics are erased, the class of V is not
available. The current implementation use the class of the array passed
as argument of the first call of the method publish() . This is clearly wrong.

Two solutions :
  - don't use an array in the signature of process() but use a List instead
  - take the class of V in the constructor.
    public SwingWorker(Class<T> tClass) {...}
      
Note : i had reviewed the SwingWorker code when it was integrated to
mustang (i think a year ago), it troubles me because
it mix runtime type and generics but i was not able to produce a test case
that show my insight until today.
So the test case is not issue from a real application.

R��mi Forax

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run the code

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
it should work
ACTUAL -
it throws a ClassCastException

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "AWT-EventQueue-0" java.lang.ArrayStoreException
	at java.lang.System.arraycopy(Native Method)
	at java.util.ArrayList.toArray(ArrayList.java:306)
	at sun.swing.AccumulativeRunnable.flush(AccumulativeRunnable.java:148)
	at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:96)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:598)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.SwingWorker;

public class SwingWorkerTest {
    public static void main(String[] args) {
      new SwingWorker<Void,CharSequence>() {
        @Override
        protected Void doInBackground() {
          publish(new String[] {"hello"});
          publish(new StringBuilder("world"));
          return null;
        }
      }.execute();
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Add this line
publish(new CharSequence[0]);
as the first line of doInBackground().

Comments
EVALUATION Description suggests two solutions: - don't use an array in the signature of process() but use a List instead - take the class of V in the constructor. There is a third one semi-solution - do better guessing of V. The problem is no matter how good guessing is it is going to be guessing only and there will be cases when the guess going to be wrong. For the SwingWorker.process method there are no advantages of using V[] versus List<V> as an argument. I am going to change signature of this method to protected void process(List<V> chunks)
06-06-2006