Reputation: 36703
I've encountered the following error when opening a ComboBox with prompt type and a StringConverter attached using Java 1.8u40. This was traced back to example strings left by the team doing the FXML, conflicting with a generically typed ComboBox in the Controller. We fixed this by ensuring the dummy list is replaced with items of the correct type in the initialize().
However whilst I understand the problem and how to solve it, I cannot understand the stack trace... The error occurs on at Controller$1.toString(Controller.java:1)
Original error
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at Controller$1.toString(Controller.java:1)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.updateDisplayText(ComboBoxListViewSkin.java:388)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.access$100(ComboBoxListViewSkin.java:57)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin$2$1.updateItem(ComboBoxListViewSkin.java:425)
at javafx.scene.control.ListCell.updateItem(ListCell.java:471)
at javafx.scene.control.ListCell.indexChanged(ListCell.java:330)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1957)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1797)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCellBreadth(VirtualFlow.java:1888)
at com.sun.javafx.scene.control.skin.VirtualFlow.getMaxCellWidth(VirtualFlow.java:2508)
at com.sun.javafx.scene.control.skin.VirtualContainerBase.getMaxCellWidth(VirtualContainerBase.java:94)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin$3.computePrefWidth(ComboBoxListViewSkin.java:457)
at javafx.scene.Parent.prefWidth(Parent.java:904)
at javafx.scene.layout.Region.prefWidth(Region.java:1419)
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.sizePopup(ComboBoxPopupControl.java:199)
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.positionAndShowPopup(ComboBoxPopupControl.java:173)
at com.sun.javafx.scene.control.skin.ComboBoxPopupControl.show(ComboBoxPopupControl.java:154)
at com.sun.javafx.scene.control.skin.ComboBoxBaseSkin.handleControlPropertyChanged(ComboBoxBaseSkin.java:127)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.handleControlPropertyChanged(ComboBoxListViewSkin.java:159)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:178)
at javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl.access$100(ReadOnlyBooleanWrapper.java:148)
at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:144)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
at javafx.scene.control.ComboBoxBase.setShowing(ComboBoxBase.java:185)
at javafx.scene.control.ComboBoxBase.show(ComboBoxBase.java:391)
at com.sun.javafx.scene.control.behavior.ComboBoxBaseBehavior.show(ComboBoxBaseBehavior.java:242)
at com.sun.javafx.scene.control.behavior.ComboBoxBaseBehavior.mouseReleased(ComboBoxBaseBehavior.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$351(GlassViewEventHandler.java:385)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
I've used Integer to represent some other business specific type, too complex to paste here, the list of values is actually dynamic and loaded from a database
FXML
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="205.0" prefWidth="168.0" styleClass="layout" xmlns:fx="http://javafx.com/fxml" fx:controller="Controller">
<children>
<ComboBox fx:id="combo" prefWidth="200" promptText="...">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Foo" />
<String fx:value="Bar" />
<String fx:value="Baz" />
</FXCollections>
</items>
</ComboBox>
</children>
</AnchorPane>
Controller
public class Controller implements Initializable {
@FXML
private ComboBox<Integer> combo;
@Override
public void initialize(URL location, ResourceBundle resources) {
combo.setConverter(new StringConverter<Integer>() {
@Override
public String toString(Integer object) {
return "custom " + object.intValue();
}
@Override
public Integer fromString(String string) {
return null;
}
});
}
}
Main
public class ComboBoxTypeMismatch extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
try {
stage.setScene(new Scene(FXMLLoader.load(getClass().getResource("/test.fxml"))));
} catch (IOException e) {
e.printStackTrace();
}
stage.show();
}
}
Upvotes: 1
Views: 732
Reputation: 4091
Is there some compiler generated magic involved?
Indeed, and there is why:
Normally, one should have one class per file. It means that every .java file produces a .class file after beeing compiled.
Now your file Controller.java contains at least 2 classes: Controller
and an anonymous class: new StringConverter<Integer>() {...};
. So, when Controller.java got compiled, the output must be stored in 2 files.
The convention taken by the java compiler to name the second file is: EnclosingClass$n.class where n is the n-th anonymous class in the enclosing class.
If you go in your bin directory you will see both files, Controller.class and Controller$1.class (and maybe more).
Why is this reported at line 1, Controller itself is not generic, only its fields...?
As you said, it seems a specific compiler version issue.
How could the FXML building process build a ComboBox of the correct type as generics only exist at compile type?
Where are generics involved ? In your code you declared ComboBox<Integer>
.
Upvotes: 1
Reputation: 36742
Although this answer isn't a solution to OP's original question, I am still leaving this for someone who comes around with the same stacktrace and doesn't know what went wrong.
You are declaring a ComboBox<Integer>
in your controller, where as you are passing String values to it in the FXML and therefore the exception.
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
If you want to have a ComboBox which contains Integer value, then you need to pass Integer values to your ComboBox.
<FXCollections fx:factory="observableArrayList">
<Integer fx:value="1" />
<Integer fx:value="2" />
<Integer fx:value="3" />
</FXCollections>
Upvotes: 3
Reputation: 36703
This appears to be a compiler issue, specifically the internal compiler used in Eclipse, Luna SR1.
If the same example is compiled using the JDK compiler the error is reported correctly at line 14
javac Controller.java
javac ComboBoxTypeMismatch.java
java -cp . ComboBoxTypeMismatch
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at Controller$1.toString(Controller.java:14)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.updateDisplayText(ComboBoxListViewSkin.java:388)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.access$100(ComboBoxListViewSkin.java:57)
at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin$2$1.updateItem(ComboBoxListViewSkin.java:425)
at javafx.scene.control.ListCell.updateItem(ListCell.java:471)
Upvotes: 1