JDK-6423212 : ClassCastException in JSpinner with decimal numbers
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86
  • Submitted: 2006-05-08
  • Updated: 2010-04-02
  • Resolved: 2006-05-26
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)

java version "1.6.0-beta2"
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b79)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b79, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Linux linux 2.6.11.4-20a-default #1 Wed Mar 23 21:52:37 UTC 2005 x86_64 x86_64 x86_64 GNU/Linux

Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
I'm trying to create a JSpinner control to enter a currency amount starting from ��1.00.  When I pass an initial value into the JSpinner constructor of 1.00 I receive a ClassCastException the first time I select the increment button on the spinner.  However, when I pass an initial value of 1.01 the spinner works as expected.  It would appear the system is interpreting the value '1.00' as a long integer instead of a double. 

Consider the following JSpinner constructor invocation:

amountSpinner = new JSpinner(
                new SpinnerNumberModel(1.00, 0.00, Double.MAX_VALUE, 1.00));

The call to the JSpinner constructor above generates an error but the following SpinnerNumberModel(1.01, 0.00, Double.MAX_VALUE, 1.00) works ok!

P.S. Is there a more elegant way to set the format of the JFormattedTextField?  Although you can pass a format pattern string into the constructor for the JSpinner.Editor I cannot work out how to obtain the required string from NumberFormat.getCurrencyInstance().

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. javac MainFrame.java
2. java MainFrame
3. Select the increment button on the JSpinner control and you should receive a ClassCastException immediately.

Then try the same procedure but using thevalues (1.01, 0.00, Double.MAX_VALUE, 1.00).  When you press the increment button the spinner should work as expected.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The spinner should increment the currency amount displayed from ��1.00 to ��2.00.
ACTUAL -
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.L
ong cannot be cast to java.lang.Double
        at java.lang.Double.compareTo(Double.java:32)
        at javax.swing.SpinnerNumberModel.incrValue(SpinnerNumberModel.java:332)

        at javax.swing.SpinnerNumberModel.getNextValue(SpinnerNumberModel.java:3
55)
        at javax.swing.JSpinner.getNextValue(JSpinner.java:347)
        at javax.swing.plaf.basic.BasicSpinnerUI$ArrowButtonHandler.actionPerfor
med(BasicSpinnerUI.java:629)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:19
82)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.jav
a:2305)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel
.java:377)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:232
)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonL
istener.java:236)
        at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:2
31)
        at java.awt.Component.processMouseEvent(Component.java:5979)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3284)
        at java.awt.Component.processEvent(Component.java:5744)
        at java.awt.Container.processEvent(Container.java:1984)
        at java.awt.Component.dispatchEventImpl(Component.java:4387)
        at java.awt.Container.dispatchEventImpl(Container.java:2042)
        at java.awt.Component.dispatchEvent(Component.java:4217)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4246
)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3910)

        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3840)
        at java.awt.Container.dispatchEventImpl(Container.java:2028)
        at java.awt.Window.dispatchEventImpl(Window.java:2297)
        at java.awt.Component.dispatchEvent(Component.java:4217)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThre
ad.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.
java:183)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThre
ad.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 :
See the Actual Result information above.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.FlowLayout;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.NumberFormatter;

public class MainFrame extends JFrame
{
    private static MainFrame window;

    private JSpinner amountSpinner;
    
    public MainFrame()
    {
        super("Demo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 300);
        setLocationRelativeTo(null);
        layoutComponents();
        setVisible(true);
    }
    
    public static void main(String[] args)
    {
        window = new MainFrame();
    }
    
    private void layoutComponents()
    {
        setLayout(new FlowLayout());
        amountSpinner = new JSpinner(
                new SpinnerNumberModel(1.00f, 0.00f, Double.MAX_VALUE, 1.00f));
        JSpinner.NumberEditor amountEditor = new JSpinner.NumberEditor(
                amountSpinner);
        amountSpinner.setEditor(amountEditor);
        JFormattedTextField jftf2 = amountEditor.getTextField();
        jftf2.setFormatterFactory(new DefaultFormatterFactory(
                new NumberFormatter(NumberFormat.getCurrencyInstance())));
        jftf2.setColumns(8);
        add(amountSpinner);
    }
}
---------- END SOURCE ----------

Comments
08-06-2006

EVALUATION Just to confuse us, NumberFormat's currency instance doesn't always return the same type. If passed in 1.00 it'll return Long. On the other hand if passed in 1.01 it'll return Double. Nice eh? I've filed a bug on NumberFormat to spec this out better (6431110). So, the reason the exception is being thrown is the SPinnerNumberModel's value type is Double, where as with a value of 1.00 jformattedtextfield (because of the NumberFormat) will give a value of Long. Double and Long aren't comparable, hence the exception. You can force NumberFormatter to always return a certain type by invoking setValueClass(). So, if you change the code to invoke numberFormatter.setValueClass(Double.class) all is well.
26-05-2006