<Swing Dev> JDK 9 RFR of JDK-8054360: Refine generification of javax.swing

Joe Darcy joe.darcy at oracle.com
Fri Aug 8 02:20:55 UTC 2014


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);





More information about the swing-dev mailing list