Hello,

Please review my changes for

    JDK-8054360: Refine generification of javax.swing h
http://cr.openjdk.java.net/~darcy/8054360.3/

Full patch below.

This resolves many of the source incompatibility exemplars Jan Lahoda found in a corpus of programs using swing.

A few comments on the changes.

It seems many existing implementations of the TreeNode interface have a covariant override of the old raw

    Enumeration children();

method which returns an enumeration of the specific TreeNode implementation type. The revised generification of

    Enumeration<? extends TreeNode> children();

allows those existing implementations to still compile. This is a lower-impact way of allowing those types to still compile compared to trying to add a type variable to TreeNode.

After some expert generics advice from Dan Smith, I but together a different generification of

    src/share/classes/javax/swing/table/DefaultTableModel.java

which has better source compatibility. Quoting from the changes:

  73     @SuppressWarnings("rawtypes")
  74     protected Vector<Vector>    dataVector;
  75
  76     /** The <code>Vector</code> of column identifiers. */
  77     @SuppressWarnings("rawtypes")
  78     protected Vector    columnIdentifiers;
  79     // Unfortunately, for greater source compatibility the inner-most
  80     // Vector in the two fields above is being left raw. The Vector is
  81     // read as well as written so using Vector<?> is not suitable and
  82     // using Vector<Object> (without adding copying of input Vectors),
  83     // would disallow existing code that used, say, a Vector<String>
  84     // as an input parameter.

The setter methods used for these fields are changes to have parameters of type Vector<?> and Vector<? extends Vector>, respectively.

The type Vector<? extends Vector> is the most general type which captures the implicit constraint of the dataVector field: it is a Vector of other Vectors. (It would probably be possible to update dataVector to the somewhat more general Vector<List>, but that would require changes to the code in other methods of the class.)

The changes in src/share/classes/sun/tools/jconsole/inspector/TableSorter.java change the code back to how it was before the swing generification changes went in based on the changes to DefaultTableModel.

Once the exact generification is settled, I'll file the internal ccc paperwork.

Early feedback on using this revised generification on swing code is welcome!

Thanks,

-Joe

--- old/src/share/classes/javax/swing/JSlider.java 2014-08-07 16:53:58.000000000 -0700 +++ new/src/share/classes/javax/swing/JSlider.java 2014-08-07 16:53:58.000000000 -0700
@@ -138,7 +138,7 @@
     /**
      * {@code Dictionary} of what labels to draw at which values
      */
-    private Dictionary<Integer, JComponent> labelTable;
+    private Dictionary<Integer, ? extends JComponent> labelTable;


     /**
@@ -773,7 +773,7 @@
         }

         // Check that there is a label with such image
-        Enumeration<JComponent> elements = labelTable.elements();
+        Enumeration<? extends JComponent> elements = labelTable.elements();

         while (elements.hasMoreElements()) {
             JComponent component = elements.nextElement();
@@ -797,7 +797,7 @@
      * @return the <code>Dictionary</code> containing labels and
      *    where to draw them
      */
-    public Dictionary<Integer, JComponent> getLabelTable() {
+    public Dictionary<Integer, ? extends JComponent> getLabelTable() {
 /*
         if ( labelTable == null && getMajorTickSpacing() > 0 ) {
setLabelTable( createStandardLabels( getMajorTickSpacing() ) );
@@ -830,8 +830,8 @@
      *    attribute: visualUpdate true
* description: Specifies what labels will be drawn for any given value.
      */
-    public void setLabelTable( Dictionary<Integer, JComponent> labels ) {
-        Dictionary<Integer, JComponent> oldTable = labelTable;
+ public void setLabelTable( Dictionary<Integer, ? extends JComponent> labels ) {
+        Dictionary<Integer, ? extends JComponent> oldTable = labelTable;
         labelTable = labels;
         updateLabelUIs();
         firePropertyChange("labelTable", oldTable, labelTable );
@@ -852,7 +852,7 @@
      * @see JComponent#updateUI
      */
     protected void updateLabelUIs() {
-        Dictionary<Integer, JComponent> labelTable = getLabelTable();
+ Dictionary<Integer, ? extends JComponent> labelTable = getLabelTable();

         if (labelTable == null) {
             return;
@@ -866,9 +866,9 @@
     }

     private void updateLabelSizes() {
-        Dictionary<Integer, JComponent> labelTable = getLabelTable();
+ Dictionary<Integer, ? extends JComponent> labelTable = getLabelTable();
         if (labelTable != null) {
-            Enumeration<JComponent> labels = labelTable.elements();
+ Enumeration<? extends JComponent> labels = labelTable.elements();
             while (labels.hasMoreElements()) {
                 JComponent component = labels.nextElement();
                 component.setSize(component.getPreferredSize());
@@ -1017,7 +1017,7 @@

         SmartHashtable table = new SmartHashtable( increment, start );

-        Dictionary<Integer, JComponent> labelTable = getLabelTable();
+ Dictionary<Integer, ? extends JComponent> labelTable = getLabelTable();

if (labelTable != null && (labelTable instanceof PropertyChangeListener)) { removePropertyChangeListener((PropertyChangeListener) labelTable); --- old/src/share/classes/javax/swing/JTable.java 2014-08-07 16:53:59.000000000 -0700 +++ new/src/share/classes/javax/swing/JTable.java 2014-08-07 16:53:59.000000000 -0700
@@ -669,7 +669,8 @@
      * @param rowData           the data for the new table
      * @param columnNames       names of each column
      */
- public JTable(Vector<Vector<Object>> rowData, Vector<Object> columnNames) {
+    @SuppressWarnings("rawtypes")
+ public JTable(Vector<? extends Vector> rowData, Vector<?> columnNames) {
         this(new DefaultTableModel(rowData, columnNames));
     }

--- old/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java 2014-08-07 16:54:00.000000000 -0700 +++ new/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java 2014-08-07 16:54:00.000000000 -0700
@@ -397,10 +397,10 @@
     protected boolean labelsHaveSameBaselines() {
         if (!checkedLabelBaselines) {
             checkedLabelBaselines = true;
-            Dictionary<?, JComponent> dictionary = slider.getLabelTable();
+ Dictionary<Integer, ? extends JComponent> dictionary = slider.getLabelTable();
             if (dictionary != null) {
                 sameLabelBaselines = true;
-                Enumeration<JComponent> elements = dictionary.elements();
+ Enumeration<? extends JComponent> elements = dictionary.elements();
                 int baseline = -1;
                 while (elements.hasMoreElements()) {
                     JComponent label = elements.nextElement();
@@ -753,7 +753,7 @@
     }

     protected int getWidthOfWidestLabel() {
-        Dictionary<?, JComponent> dictionary = slider.getLabelTable();
+ Dictionary<?, ? extends JComponent> dictionary = slider.getLabelTable();
         int widest = 0;
         if ( dictionary != null ) {
             Enumeration<?> keys = dictionary.keys();
@@ -766,7 +766,7 @@
     }

     protected int getHeightOfTallestLabel() {
-        Dictionary<?, JComponent> dictionary = slider.getLabelTable();
+ Dictionary<?, ? extends JComponent> dictionary = slider.getLabelTable();
         int tallest = 0;
         if ( dictionary != null ) {
             Enumeration<?> keys = dictionary.keys();
@@ -871,7 +871,7 @@
      * @since 1.6
      */
     protected Integer getLowestValue() {
- Dictionary<Integer, JComponent> dictionary = slider.getLabelTable(); + Dictionary<Integer, ? extends JComponent> dictionary = slider.getLabelTable();

         if (dictionary == null) {
             return null;
@@ -1121,7 +1121,7 @@
     public void paintLabels( Graphics g ) {
         Rectangle labelBounds = labelRect;

- Dictionary<Integer, JComponent> dictionary = slider.getLabelTable(); + Dictionary<Integer, ? extends JComponent> dictionary = slider.getLabelTable();
         if ( dictionary != null ) {
             Enumeration<Integer> keys = dictionary.keys();
             int minValue = slider.getMinimum();
--- old/src/share/classes/javax/swing/plaf/synth/SynthSliderUI.java 2014-08-07 16:54:02.000000000 -0700 +++ new/src/share/classes/javax/swing/plaf/synth/SynthSliderUI.java 2014-08-07 16:54:01.000000000 -0700
@@ -392,7 +392,7 @@
                 trackRect.x = insetCache.left;
                 trackRect.width = contentRect.width;

- Dictionary<Integer, JComponent> dictionary = slider.getLabelTable(); + Dictionary<Integer, ? extends JComponent> dictionary = slider.getLabelTable();
                 if (dictionary != null) {
                     int minValue = slider.getMinimum();
                     int maxValue = slider.getMaximum();
--- old/src/share/classes/javax/swing/table/DefaultTableModel.java 2014-08-07 16:54:03.000000000 -0700 +++ new/src/share/classes/javax/swing/table/DefaultTableModel.java 2014-08-07 16:54:02.000000000 -0700
@@ -70,10 +70,18 @@
      * The <code>Vector</code> of <code>Vectors</code> of
      * <code>Object</code> values.
      */
-    protected Vector<Vector<Object>>    dataVector;
+    @SuppressWarnings("rawtypes")
+    protected Vector<Vector>    dataVector;

     /** The <code>Vector</code> of column identifiers. */
-    protected Vector<Object>    columnIdentifiers;
+    @SuppressWarnings("rawtypes")
+    protected Vector    columnIdentifiers;
+    // Unfortunately, for greater source compatibility the inner-most
+    // Vector in the two fields above is being left raw. The Vector is
+    // read as well as written so using Vector<?> is not suitable and
+    // using Vector<Object> (without adding copying of input Vectors),
+    // would disallow existing code that used, say, a Vector<String>
+    // as an input parameter.

 //
 // Constructors
@@ -121,7 +129,7 @@
      * @see #setDataVector
      * @see #setValueAt
      */
-    public DefaultTableModel(Vector<Object> columnNames, int rowCount) {
+    public DefaultTableModel(Vector<?> columnNames, int rowCount) {
         setDataVector(newVector(rowCount), columnNames);
     }

@@ -156,7 +164,8 @@
      * @see #getDataVector
      * @see #setDataVector
      */
- public DefaultTableModel(Vector<Vector<Object>> data, Vector<Object> columnNames) {
+    @SuppressWarnings("rawtypes")
+ public DefaultTableModel(Vector<? extends Vector> data, Vector<?> columnNames) {
         setDataVector(data, columnNames);
     }

@@ -191,7 +200,8 @@
      * @see #newRowsAdded
      * @see #setDataVector
      */
-    public Vector<Vector<Object>> getDataVector() {
+    @SuppressWarnings("rawtypes")
+    public Vector<Vector> getDataVector() {
         return dataVector;
     }

@@ -219,9 +229,10 @@
      * @param   columnIdentifiers     the names of the columns
      * @see #getDataVector
      */
-    public void setDataVector(Vector<Vector<Object>> dataVector,
-                              Vector<Object> columnIdentifiers) {
-        this.dataVector = nonNullVector(dataVector);
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void setDataVector(Vector<? extends Vector> dataVector,
+                              Vector<?> columnIdentifiers) {
+        this.dataVector = nonNullVector((Vector<Vector>)dataVector);
         this.columnIdentifiers = nonNullVector(columnIdentifiers);
         justifyRows(0, getRowCount());
         fireTableStructureChanged();
@@ -267,7 +278,7 @@
             if (dataVector.elementAt(i) == null) {
                 dataVector.setElementAt(new Vector<>(), i);
             }
- ((Vector)dataVector.elementAt(i)).setSize(getColumnCount());
+            dataVector.elementAt(i).setSize(getColumnCount());
         }
     }

@@ -350,7 +361,7 @@
      *
      * @param   rowData          optional data of the row being added
      */
-    public void addRow(Vector<Object> rowData) {
+    public void addRow(Vector<?> rowData) {
         insertRow(getRowCount(), rowData);
     }

@@ -374,7 +385,7 @@
      * @param   rowData         optional data of the row being added
      * @exception  ArrayIndexOutOfBoundsException  if the row was invalid
      */
-    public void insertRow(int row, Vector<Object> rowData) {
+    public void insertRow(int row, Vector<?> rowData) {
         dataVector.insertElementAt(rowData, row);
         justifyRows(row, row+1);
         fireTableRowsInserted(row, row);
@@ -484,7 +495,7 @@
      *                          to zero columns
      * @see #setNumRows
      */
-    public void setColumnIdentifiers(Vector<Object> columnIdentifiers) {
+    public void setColumnIdentifiers(Vector<?> columnIdentifiers) {
         setDataVector(dataVector, columnIdentifiers);
     }

@@ -550,7 +561,8 @@
      * @param   columnName the identifier of the column being added
      * @param   columnData       optional data of the column being added
      */
-    public void addColumn(Object columnName, Vector<Object> columnData) {
+ @SuppressWarnings("unchecked") // Adding element to raw columnIdentifiers
+    public void addColumn(Object columnName, Vector<?> columnData) {
         columnIdentifiers.addElement(columnName);
         if (columnData != null) {
             int columnSize = columnData.size();
@@ -652,6 +664,7 @@
      *               column was given
      */
     public Object getValueAt(int row, int column) {
+        @SuppressWarnings("unchecked")
         Vector<Object> rowVector = dataVector.elementAt(row);
         return rowVector.elementAt(column);
     }
@@ -668,6 +681,7 @@
      *               column was given
      */
     public void setValueAt(Object aValue, int row, int column) {
+        @SuppressWarnings("unchecked")
         Vector<Object> rowVector = dataVector.elementAt(row);
         rowVector.setElementAt(aValue, column);
         fireTableCellUpdated(row, column);
--- old/src/share/classes/javax/swing/tree/DefaultMutableTreeNode.java 2014-08-07 16:54:04.000000000 -0700 +++ new/src/share/classes/javax/swing/tree/DefaultMutableTreeNode.java 2014-08-07 16:54:04.000000000 -0700
@@ -1308,7 +1308,7 @@
     }

private final class PreorderEnumeration implements Enumeration<TreeNode> {
-        private final Stack<Enumeration<TreeNode>> stack = new Stack<>();
+ private final Stack<Enumeration<? extends TreeNode>> stack = new Stack<>();

         public PreorderEnumeration(TreeNode rootNode) {
             super();
@@ -1322,10 +1322,9 @@
         }

         public TreeNode nextElement() {
-            Enumeration<TreeNode> enumer = stack.peek();
+            Enumeration<? extends TreeNode> enumer = stack.peek();
             TreeNode    node = enumer.nextElement();
-            @SuppressWarnings("unchecked")
-            Enumeration<TreeNode> children = node.children();
+            Enumeration<? extends TreeNode> children = node.children();

             if (!enumer.hasMoreElements()) {
                 stack.pop();
@@ -1342,7 +1341,7 @@

     final class PostorderEnumeration implements Enumeration<TreeNode> {
         protected TreeNode root;
-        protected Enumeration<TreeNode> children;
+        protected Enumeration<? extends TreeNode> children;
         protected Enumeration<TreeNode> subtree;

         public PostorderEnumeration(TreeNode rootNode) {
--- old/src/share/classes/javax/swing/tree/TreeNode.java 2014-08-07 16:54:05.000000000 -0700 +++ new/src/share/classes/javax/swing/tree/TreeNode.java 2014-08-07 16:54:05.000000000 -0700
@@ -99,5 +99,5 @@
      *
* @return the children of the receiver as an {@code Enumeration}
      */
-    Enumeration<TreeNode> children();
+    Enumeration<? extends TreeNode> children();
 }
--- old/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java 2014-08-07 16:54:06.000000000 -0700 +++ new/src/share/classes/sun/tools/jconsole/inspector/TableSorter.java 2014-08-07 16:54:06.000000000 -0700
@@ -146,7 +146,7 @@
// update row heights in XMBeanAttributes (required by expandable cells)
         if (attrs != null) {
             for (int i = 0; i < getRowCount(); i++) {
-                Vector<?> data = (Vector) dataVector.elementAt(i);
+                Vector<?> data = dataVector.elementAt(i);
                 attrs.updateRowHeight(data.elementAt(1), i);
             }
         }
@@ -217,17 +217,17 @@
             }
     }

-    private Vector<Object> getRow(int row) {
+    private Vector<?> getRow(int row) {
         return dataVector.elementAt(row);
     }

     @SuppressWarnings("unchecked")
-    private void setRow(Vector<Object> data, int row) {
+    private void setRow(Vector<?> data, int row) {
         dataVector.setElementAt(data,row);
     }

     private void swap(int i, int j, int column) {
-        Vector<Object> data = getRow(i);
+        Vector<?> data = getRow(i);
         setRow(getRow(j),i);
         setRow(data,j);


Reply via email to