RowFilter.NumberFilter:无法处理“混合”具体数字类型

时间:2011-11-03 10:45:21

标签: java swing numbers compare rowfilter

如果至少有一个值(值= = RowFilter中的值,条目中的值)是小数,则会发生。这是一个失败的测试:

@Test
public void testRowFilterNumberMixCore() {
    TestEntry entry = new TestEntry(1.2f);
    RowFilter filter = RowFilter.numberFilter(ComparisonType.AFTER, 1, 0);
    assertTrue(entry + "must be included " + filter, filter.include(entry));
}

输出结果为:

junit.framework.AssertionFailedError: 
[entry: 1.2] must be included [RowFilter: ComparisonType = AFTER, comparableValue: 1, comparableClass: class java.lang.Integer]

原因是NumberFilter回退到将数字与它们的数字进行比较.longValue()如果它们不是同一个类(并且相互比较)

知道细节,测试失败并不令人惊讶(在后视中,从未想过这是一个问题;-)一个级别的防御是确保 - 在客户端代码中 - 要比较的数字< em>是同一类的。这并不总是可能的(想想f.i:tableColumn with columnClass Number)所以我想知道是否/如何改进后备。类似的东西:

if (one instanceof Comparable && one.getClass() == other.getClass()) {
    // same class, use comparator
    return ((Comparable) one).compareTo(other);
}
if (areIntegers(one, other)) {
    // all integers, use longValue
    return longCompare(one, other);
}
if (areDecimals(one, other)) {
    // anything to do here?
}
// at last resort convert to BigDecimal and compare those: 
BigDecimal bigOne = new BigDecimal(one.toString());
BigDecimal bigOther = new BigDecimal(other.toString());
return bigOne.compareTo(bigOther);

这样做,让测试通过 - 我对隐藏(读:我不知道)陷阱有点警惕。任何警告/替代品都非常欢迎!

仅供参考:交叉发布到OTN's Swing forum

后续

如上所述实施,现在正在等待客户投诉 - 在这种情况下会指向所有没有在此警告我的人:-)

1 个答案:

答案 0 :(得分:4)

我没有更好的答案,但下面的例子说明了效果。特别是,基于RowFilter基元的double boxedDouble,生成具有values > 1的预期画面。相反,基于float的那个被加框为Float。由于类文字不匹配,include()会比较long值,意外地过滤所有小数values < 2

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.RowFilter;
import javax.swing.RowFilter.ComparisonType;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;

/** @see http://stackoverflow.com/questions/7993546 */
public class FilterTest {

    private static TableRowSorter<TableModel> sorter;
    private static RowFilter<TableModel, Integer> dFilter;
    private static RowFilter<TableModel, Integer> fFilter;
    private static boolean b;

    public static void main(String[] args) {
        TableModel model = new TableModel();
        JTable table = new JTable(model);
        sorter = new TableRowSorter<TableModel>(model);
        dFilter = RowFilter.numberFilter(ComparisonType.AFTER, 1d, 0);
        fFilter = RowFilter.numberFilter(ComparisonType.AFTER, 1f, 0);
        sorter.setRowFilter(dFilter);
        table.setRowSorter(sorter);
        JScrollPane scrollPane = new JScrollPane(table);
        table.setPreferredScrollableViewportSize(new Dimension(320, 240));

        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(scrollPane, BorderLayout.CENTER);
        f.add(new JToggleButton(new AbstractAction("Toggle") {

            @Override
            public void actionPerformed(ActionEvent e) {
                b = !b;
                if (b) {
                    sorter.setRowFilter(fFilter);
                } else {
                    sorter.setRowFilter(dFilter);
                }
            }
        }), BorderLayout.SOUTH);

        f.pack();
        f.setVisible(true);
    }

    private static class TableModel extends AbstractTableModel {

        private static final int ROWS = 16;
        private static final int COLS = 4;
        private Double[][] matrix = new Double[ROWS][COLS];

        public TableModel() {
            double v = 0;
            for (Object[] row : matrix) {
                Arrays.fill(row, Double.valueOf(v += 0.25));
            }
        }

        @Override
        public int getRowCount() {
            return ROWS;
        }

        @Override
        public int getColumnCount() {
            return COLS;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return matrix[row][col];
        }

        @Override
        public Class<?> getColumnClass(int col) {
            return Number.class;
        }
    }
}