-
Bug
-
Resolution: Fixed
-
P4
-
6
-
b17
-
x86
-
solaris_10
FULL PRODUCT VERSION :
java version "1.6.0-rc"
A DESCRIPTION OF THE PROBLEM :
After the first time a JTableHeader is Serialized it no longer will uninstall its UI upon subsequent Serializations. The problem is that the JTableHeader does not implement writeObject to participate in Swing's Serialization mechanism correctly. Each time an JComponent instance is Serialized, a counter for the instance is incremented. It is de-incremented in JComponent's writeObject or a class that implements it the same way. With JTableHeader it does not deincrement the counter. The uninstall mechanism will not uninstall a UI if the counter is not 0 on the first pass. Hence, after the first Serialzation the JTableHeader has a counter of 1. This increases with each pass. What makes this problem worse is that upon each pass, if the JTableHeader serializes correctly, the UI reinstalls itself again. This means the same UI listeners add N+ times. This happens for classes that use the BasicTableHeaderUI class. Any LAF that uses the SynthLookAndFeel will get an NotSerializableException thrown.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this test case, try it with a Synth LAF like GTK:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;
import java.io.*;
public class SerializeJTableHeader implements Runnable{
public void run(){
JTableHeader jth = new JTableHeader();
try{
for(int i = 0; i < 10; i ++){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
System.out.println(jth.getUI());
oos.writeObject(jth);
oos.writeObject(jth.getAccessibleContext());
}
}
catch(Exception x){ x.printStackTrace(); }
}
public static void main(String ... args){
try{
int i = Integer.parseInt(args[0]);
if(i == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(i == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
} catch(Exception x){}
SwingUtilities.invokeLater(new SerializeJTableHeader());
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Everything runs fine.
ACTUAL -
An Exception can be tossed:
java.io.NotSerializableException: javax.swing.plaf.synth.SynthTableHeaderUI
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1151) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:416)
at javax.swing.JComponent.writeObject(JComponent.java:5391)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:589)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1456)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at SerializeJTableHeader.run(SerializeJTableHeader.java:15)
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)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.NotSerializableException: javax.swing.plaf.synth.SynthTableHeaderUI
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1151) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:416)
at javax.swing.JComponent.writeObject(JComponent.java:5391)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:589)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1456)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at SerializeJTableHeader.run(SerializeJTableHeader.java:15)
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.*;
import javax.swing.table.*;
import java.awt.event.*;
import java.io.*;
public class SerializeJTableHeader implements Runnable{
public void run(){
JTableHeader jth = new JTableHeader();
try{
for(int i = 0; i < 10; i ++){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
System.out.println(jth.getUI());
oos.writeObject(jth);
oos.writeObject(jth.getAccessibleContext());
}
}
catch(Exception x){ x.printStackTrace(); }
}
public static void main(String ... args){
try{
int i = Integer.parseInt(args[0]);
if(i == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(i == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
} catch(Exception x){}
SwingUtilities.invokeLater(new SerializeJTableHeader());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Must write a mechanism that uninstalls the UI for each Serialization.
java version "1.6.0-rc"
A DESCRIPTION OF THE PROBLEM :
After the first time a JTableHeader is Serialized it no longer will uninstall its UI upon subsequent Serializations. The problem is that the JTableHeader does not implement writeObject to participate in Swing's Serialization mechanism correctly. Each time an JComponent instance is Serialized, a counter for the instance is incremented. It is de-incremented in JComponent's writeObject or a class that implements it the same way. With JTableHeader it does not deincrement the counter. The uninstall mechanism will not uninstall a UI if the counter is not 0 on the first pass. Hence, after the first Serialzation the JTableHeader has a counter of 1. This increases with each pass. What makes this problem worse is that upon each pass, if the JTableHeader serializes correctly, the UI reinstalls itself again. This means the same UI listeners add N+ times. This happens for classes that use the BasicTableHeaderUI class. Any LAF that uses the SynthLookAndFeel will get an NotSerializableException thrown.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this test case, try it with a Synth LAF like GTK:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.event.*;
import java.io.*;
public class SerializeJTableHeader implements Runnable{
public void run(){
JTableHeader jth = new JTableHeader();
try{
for(int i = 0; i < 10; i ++){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
System.out.println(jth.getUI());
oos.writeObject(jth);
oos.writeObject(jth.getAccessibleContext());
}
}
catch(Exception x){ x.printStackTrace(); }
}
public static void main(String ... args){
try{
int i = Integer.parseInt(args[0]);
if(i == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(i == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
} catch(Exception x){}
SwingUtilities.invokeLater(new SerializeJTableHeader());
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Everything runs fine.
ACTUAL -
An Exception can be tossed:
java.io.NotSerializableException: javax.swing.plaf.synth.SynthTableHeaderUI
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1151) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:416)
at javax.swing.JComponent.writeObject(JComponent.java:5391)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:589)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1456)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at SerializeJTableHeader.run(SerializeJTableHeader.java:15)
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)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.NotSerializableException: javax.swing.plaf.synth.SynthTableHeaderUI
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1151) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1504)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:416)
at javax.swing.JComponent.writeObject(JComponent.java:5391)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:589)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1456)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1145) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at SerializeJTableHeader.run(SerializeJTableHeader.java:15)
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.*;
import javax.swing.table.*;
import java.awt.event.*;
import java.io.*;
public class SerializeJTableHeader implements Runnable{
public void run(){
JTableHeader jth = new JTableHeader();
try{
for(int i = 0; i < 10; i ++){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
System.out.println(jth.getUI());
oos.writeObject(jth);
oos.writeObject(jth.getAccessibleContext());
}
}
catch(Exception x){ x.printStackTrace(); }
}
public static void main(String ... args){
try{
int i = Integer.parseInt(args[0]);
if(i == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(i == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
} catch(Exception x){}
SwingUtilities.invokeLater(new SerializeJTableHeader());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Must write a mechanism that uninstalls the UI for each Serialization.