-
Bug
-
Resolution: Duplicate
-
P3
-
9
-
x86
-
windows_8
FULL PRODUCT VERSION :
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+111)
Java HotSpot(TM) Client VM (build 9-ea+111, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Windows 8.1 Pro 64bit
A DESCRIPTION OF THE PROBLEM :
JTable does not show datas using RowSorter that has no sortKeys but RowFilter is set.
REGRESSION. Last worked in version 8u77
ADDITIONAL REGRESSION INFORMATION:
I tested JDK version 6 to 8, this problem never occurs.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. copy source code for test case and make java source file 'Jdk9eaJTableBugFrame1.java'.
2. compile 'Jdk9eaJTableBugFrame1.java'.
3. execute java with main method of Jdk9eaJTableBugFrame1.
4. push the 'addRow' button that calls DefaultTableModel#addRow().
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
a row data should be added in JTable when you push the 'addRow' button.
ACTUAL -
no row data was added.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.table.TableRowSorter;
public class Jdk9eaJTableBugFrame1 extends JFrame {
private JPanel panel;
private JButton btnAddRow;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel defaultTableModel;
private TableRowSorter<DefaultTableModel> tableRowSorter;
private RowFilter<DefaultTableModel,Integer> rowFilter;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Jdk9eaJTableBugFrame1().setVisible(true);
}
});
}
public Jdk9eaJTableBugFrame1() {
initialize();
}
private void initialize() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(getPanel(), BorderLayout.NORTH);
getContentPane().add(getScrollPane(), BorderLayout.CENTER);
setSize(600,500);
}
private JPanel getPanel() {
if (panel == null) {
panel = new JPanel();
panel.add(getBtnAddRow());
}
return panel;
}
private JButton getBtnAddRow() {
if (btnAddRow == null) {
btnAddRow = new JButton("addRow");
btnAddRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
getDefaultTableModel().addRow(new Vector<Object>());
}
});
}
return btnAddRow;
}
private JScrollPane getScrollPane() {
if (scrollPane == null) {
scrollPane = new JScrollPane();
scrollPane.setViewportView(getTable());
}
return scrollPane;
}
private JTable getTable() {
if (table == null) {
table = new JTable();
// table = new WorkroundTable();
table.setModel(getDefaultTableModel());
table.setRowSorter(getTableRowSorter());
}
return table;
}
private DefaultTableModel getDefaultTableModel() {
if (defaultTableModel == null) {
defaultTableModel = new DefaultTableModel();
defaultTableModel.setColumnCount(5);
}
return defaultTableModel;
}
private TableRowSorter<DefaultTableModel> getTableRowSorter() {
if (tableRowSorter == null) {
tableRowSorter = new TableRowSorter<DefaultTableModel>(getDefaultTableModel());
tableRowSorter.setRowFilter(getRowFilter());
}
return tableRowSorter;
}
private RowFilter<DefaultTableModel,Integer> getRowFilter() {
if (rowFilter == null) {
rowFilter = new RowFilter<DefaultTableModel,Integer>() {
public boolean include(Entry entry) {
return true;
}
};
}
return rowFilter;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I checked difference of JTable.java source code, and I found the related change in the method JTable#tableChanged(TableModelEvent).
on JDK 8, tableChanged() always calls sortedTableChanged(RowSorterEvent,TableModelEvent) when RowSorter is set.
------------------------------------------------------------------------------------
JTable.java Line 4394-4397
------------------------------------------------------------------------------------
if (sortManager != null) {
sortedTableChanged(null, e);
return;
}
------------------------------------------------------------------------------------
but on JDK 9, tableChanged() does not calls sortedTableChanged() when RowSorter's sortKey is empty.
------------------------------------------------------------------------------------
JTable.java Line 4403-4411
------------------------------------------------------------------------------------
if (sortManager != null) {
List<? extends RowSorter.SortKey> sortKeys =
sortManager.sorter.getSortKeys();
if (sortKeys.size() != 0 &&
sortKeys.get(0).getSortOrder() != SortOrder.UNSORTED) {
sortedTableChanged(null, e);
return;
}
}
------------------------------------------------------------------------------------
so I write a sub-class of JTable and override tableChanged() method to call sortedTableChanged() method with reflection and it works fine.
However, I think that this is never strictly correct way.
the sub-class is bellow:
------------------------------------------------------------------------------------
import java.util.List;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableModel;
public class WorkroundTable extends JTable {
public void tableChanged(TableModelEvent e) {
boolean needsInvokeSortedTableChanged = false;
if("9-ea".equals(System.getProperty("java.version")) &&
e!=null && e.getFirstRow()!=TableModelEvent.HEADER_ROW) {
RowSorter<? extends TableModel> sorter = getRowSorter();
if(sorter!=null) {
List<? extends RowSorter.SortKey> sortKeys = sorter.getSortKeys();
if(sortKeys.size()==0 ||
sortKeys.get(0).getSortOrder()==SortOrder.UNSORTED) {
needsInvokeSortedTableChanged = true;
}
}
}
super.tableChanged(e);
if(needsInvokeSortedTableChanged) {
try {
java.lang.reflect.Method method =
JTable.class.getDeclaredMethod("sortedTableChanged",
RowSorterEvent.class,
TableModelEvent.class);
method.setAccessible(true);
method.invoke(this, null, e);
}
catch(Throwable ex) {
ex.printStackTrace();
}
}
}
}
------------------------------------------------------------------------------------
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+111)
Java HotSpot(TM) Client VM (build 9-ea+111, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Windows 8.1 Pro 64bit
A DESCRIPTION OF THE PROBLEM :
JTable does not show datas using RowSorter that has no sortKeys but RowFilter is set.
REGRESSION. Last worked in version 8u77
ADDITIONAL REGRESSION INFORMATION:
I tested JDK version 6 to 8, this problem never occurs.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. copy source code for test case and make java source file 'Jdk9eaJTableBugFrame1.java'.
2. compile 'Jdk9eaJTableBugFrame1.java'.
3. execute java with main method of Jdk9eaJTableBugFrame1.
4. push the 'addRow' button that calls DefaultTableModel#addRow().
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
a row data should be added in JTable when you push the 'addRow' button.
ACTUAL -
no row data was added.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.table.TableRowSorter;
public class Jdk9eaJTableBugFrame1 extends JFrame {
private JPanel panel;
private JButton btnAddRow;
private JScrollPane scrollPane;
private JTable table;
private DefaultTableModel defaultTableModel;
private TableRowSorter<DefaultTableModel> tableRowSorter;
private RowFilter<DefaultTableModel,Integer> rowFilter;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Jdk9eaJTableBugFrame1().setVisible(true);
}
});
}
public Jdk9eaJTableBugFrame1() {
initialize();
}
private void initialize() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(getPanel(), BorderLayout.NORTH);
getContentPane().add(getScrollPane(), BorderLayout.CENTER);
setSize(600,500);
}
private JPanel getPanel() {
if (panel == null) {
panel = new JPanel();
panel.add(getBtnAddRow());
}
return panel;
}
private JButton getBtnAddRow() {
if (btnAddRow == null) {
btnAddRow = new JButton("addRow");
btnAddRow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
getDefaultTableModel().addRow(new Vector<Object>());
}
});
}
return btnAddRow;
}
private JScrollPane getScrollPane() {
if (scrollPane == null) {
scrollPane = new JScrollPane();
scrollPane.setViewportView(getTable());
}
return scrollPane;
}
private JTable getTable() {
if (table == null) {
table = new JTable();
// table = new WorkroundTable();
table.setModel(getDefaultTableModel());
table.setRowSorter(getTableRowSorter());
}
return table;
}
private DefaultTableModel getDefaultTableModel() {
if (defaultTableModel == null) {
defaultTableModel = new DefaultTableModel();
defaultTableModel.setColumnCount(5);
}
return defaultTableModel;
}
private TableRowSorter<DefaultTableModel> getTableRowSorter() {
if (tableRowSorter == null) {
tableRowSorter = new TableRowSorter<DefaultTableModel>(getDefaultTableModel());
tableRowSorter.setRowFilter(getRowFilter());
}
return tableRowSorter;
}
private RowFilter<DefaultTableModel,Integer> getRowFilter() {
if (rowFilter == null) {
rowFilter = new RowFilter<DefaultTableModel,Integer>() {
public boolean include(Entry entry) {
return true;
}
};
}
return rowFilter;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I checked difference of JTable.java source code, and I found the related change in the method JTable#tableChanged(TableModelEvent).
on JDK 8, tableChanged() always calls sortedTableChanged(RowSorterEvent,TableModelEvent) when RowSorter is set.
------------------------------------------------------------------------------------
JTable.java Line 4394-4397
------------------------------------------------------------------------------------
if (sortManager != null) {
sortedTableChanged(null, e);
return;
}
------------------------------------------------------------------------------------
but on JDK 9, tableChanged() does not calls sortedTableChanged() when RowSorter's sortKey is empty.
------------------------------------------------------------------------------------
JTable.java Line 4403-4411
------------------------------------------------------------------------------------
if (sortManager != null) {
List<? extends RowSorter.SortKey> sortKeys =
sortManager.sorter.getSortKeys();
if (sortKeys.size() != 0 &&
sortKeys.get(0).getSortOrder() != SortOrder.UNSORTED) {
sortedTableChanged(null, e);
return;
}
}
------------------------------------------------------------------------------------
so I write a sub-class of JTable and override tableChanged() method to call sortedTableChanged() method with reflection and it works fine.
However, I think that this is never strictly correct way.
the sub-class is bellow:
------------------------------------------------------------------------------------
import java.util.List;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableModel;
public class WorkroundTable extends JTable {
public void tableChanged(TableModelEvent e) {
boolean needsInvokeSortedTableChanged = false;
if("9-ea".equals(System.getProperty("java.version")) &&
e!=null && e.getFirstRow()!=TableModelEvent.HEADER_ROW) {
RowSorter<? extends TableModel> sorter = getRowSorter();
if(sorter!=null) {
List<? extends RowSorter.SortKey> sortKeys = sorter.getSortKeys();
if(sortKeys.size()==0 ||
sortKeys.get(0).getSortOrder()==SortOrder.UNSORTED) {
needsInvokeSortedTableChanged = true;
}
}
}
super.tableChanged(e);
if(needsInvokeSortedTableChanged) {
try {
java.lang.reflect.Method method =
JTable.class.getDeclaredMethod("sortedTableChanged",
RowSorterEvent.class,
TableModelEvent.class);
method.setAccessible(true);
method.invoke(this, null, e);
}
catch(Throwable ex) {
ex.printStackTrace();
}
}
}
}
------------------------------------------------------------------------------------