Search code examples
javaswingclasscastexception

ClassCastExcpetion after using Double.intValue() in lambda expression


So, I have a strange problem:

I have a JSlider and a JSpinner, the Slider uses int values while the spinner accepts double values. Now I want to 'connect' them by using change listeners:

slider.addChangeListener(e -> spinner.setValue(slider.getValue()));
spinner.addChangeListener(e -> slider.setValue(((Double) spinner.getValue()).intValue()));

But for some weird reason I get a ClassCastException:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
at rt.Main.lambda$rotateTo$29(Main.java:318)
at javax.swing.JSpinner.fireStateChanged(JSpinner.java:458)
at javax.swing.JSpinner$ModelListener.stateChanged(JSpinner.java:386)
at javax.swing.AbstractSpinnerModel.fireStateChanged(AbstractSpinnerModel.java:119)
at javax.swing.SpinnerNumberModel.setValue(SpinnerNumberModel.java:447)
at javax.swing.JSpinner.setValue(JSpinner.java:354)
at rt.Main.lambda$rotateTo$28(Main.java:317)
at javax.swing.JSlider.fireStateChanged(JSlider.java:432)
at javax.swing.JSlider$ModelListener.stateChanged(JSlider.java:350)
at javax.swing.DefaultBoundedRangeModel.fireStateChanged(DefaultBoundedRangeModel.java:364)
at javax.swing.DefaultBoundedRangeModel.setRangeProperties(DefaultBoundedRangeModel.java:302)
at javax.swing.DefaultBoundedRangeModel.setValue(DefaultBoundedRangeModel.java:168)
at javax.swing.JSlider.setValue(JSlider.java:531)
at rt.Main.lambda$rotateTo$29(Main.java:318)
at javax.swing.JSpinner.fireStateChanged(JSpinner.java:458)
at javax.swing.JSpinner$ModelListener.stateChanged(JSpinner.java:386)
at javax.swing.AbstractSpinnerModel.fireStateChanged(AbstractSpinnerModel.java:119)
at javax.swing.SpinnerNumberModel.setValue(SpinnerNumberModel.java:447)
at javax.swing.JSpinner.setValue(JSpinner.java:354)
at javax.swing.plaf.basic.BasicSpinnerUI$ArrowButtonHandler.actionPerformed(BasicSpinnerUI.java:654)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:289)
at java.awt.Component.processMouseEvent(Component.java:6539)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6304)
at java.awt.Container.processEvent(Container.java:2239)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
at java.awt.Container.dispatchEventImpl(Container.java:2283)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)

I noticed the following:

  • Using System.out.println(spinner.getValue().getClass()) I get class java.lang.Double.

  • I checked the parameters on the spinner.setValue() method and it takes a primitive int.

  • Using the code spinner.addChangeListener(e -> System.out.println(((Double) spinner.getValue()).intValue())); does work without throwing an exception and prints an int.

  • I also tried different solutions like Math.round() or (int) Double.doubleValue(), until now nothing worked.

If anyone has an Idea why this happens please tell me!

Edit: While trying around some more I found out that slider.setValue(((Number) spinner.getValue()).intValue()) does work, but I would still like to now why? I checked the class returned again and it still is: java.lang.Double! Any help appreciated


Solution

  • The first listener

    slider.addChangeListener(e -> spinner.setValue(slider.getValue()));
    

    is setting the value of the spinner to an Integer - slider.getValue() returns an int that is boxed since spinner.setValue() requires an Object.

    Probably* you are using a SpinnerNumberModel which accepts any Number for its properties (see javadoc). Since the value of the spinner was changed (programmatically by first listener), its listener is also called, causing the exception since it now have an Integer as value.

    Simple test showing that the spinner gets an Integer:

    JSlider slider = new JSlider(0, 0, 9, 5);
    JSpinner spinner = new JSpinner(new SpinnerNumberModel(5.0, 0.0, 9.0, 1.0));
    
    slider.addChangeListener(e -> spinner.setValue(slider.getValue()));
    spinner.addChangeListener(e -> slider.setValue(((Number) spinner.getValue()).intValue()));
    
    JOptionPane.showMessageDialog(null, new Object[] { slider, spinner });
    System.out.println(spinner.getValue().getClass());
    

    move the slider and press OK - it will set the spinner value to an Integer.

    * missing such minimal complete example in question


    Correct solution, IMHO:

    slider.addChangeListener(e -> spinner.setValue((double)slider.getValue()));
    spinner.addChangeListener(e -> slider.setValue(((Number) spinner.getValue()).intValue()));
    

    I left the cast to Number as metallurg suggested since the model is designed to work with Number.