FULL PRODUCT VERSION :
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux XPS-15-9560 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
I call ListView.setCellFactory() and call ListCell.textProperty().bind() with a StringBinding. The StringBinding calls ListCell.itemProperty().toString(). Executing this code causes stack overflow
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following example. Select a file from the FileChooser.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
See the selected file in the ListView.
ACTUAL -
StackOverflowError
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package listview.example;
import java.io.File;
import java.util.concurrent.Callable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ObjectProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Separator;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class FileUploaderVBox extends VBox {
ListView<File> filesToUpload = new ListView<>();
public FileUploaderVBox(Stage primaryStage) {
setAlignment(Pos.TOP_CENTER);
Label l = new Label("Select Files to Upload");
l.setStyle("-fx-font: 12 arial; -fx-font-weight: bold;");
setMargin(l, new Insets(25,0,20,0));
Separator horizSeparator1 = new Separator();
horizSeparator1.prefWidthProperty().bind(widthProperty());
filesToUpload.setCellFactory(lv -> {
ListCell<File> cell = new ListCell<>();
ContextMenu contextMenu = new ContextMenu();
MenuItem deleteItem = new MenuItem();
deleteItem.textProperty().bind(Bindings.format("Delete \"%s\"", cell.itemProperty()));
deleteItem.setOnAction(event -> filesToUpload.getItems().remove(cell.getItem()));
contextMenu.getItems().addAll(deleteItem);
// cell.textProperty().bind(cell.itemProperty());
// cell.textProperty().bind(cell.itemProperty().asString());
ObjectProperty<File> itemProperty = cell.itemProperty();
// StringBinding sb = Bindings.createStringBinding(new Callable<String>() {
//
// @Override
// public String call() throws Exception {
//
// if (null == itemProperty.getValue())
// return "";
// else
// return itemProperty.getValue().toString();
// }
//
// }, itemProperty);
StringBinding sb = Bindings.createStringBinding(new Callable<String>() {
@Override
public String call() throws Exception {
if (null == itemProperty)
return "";
else
return itemProperty.toString();
}
}, itemProperty);
cell.textProperty().bind(sb);
cell.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
cell.setContextMenu(null);
} else {
cell.setContextMenu(contextMenu);
}
});
return cell ;
});
Separator horizSeparator2 = new Separator();
horizSeparator2.prefWidthProperty().bind(widthProperty());
Button chooseFileButton = new Button("Choose File");
chooseFileButton.setOnAction(new EventHandler<ActionEvent> () {
@Override
public void handle(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
File f = fileChooser.showOpenDialog(primaryStage);
if (null != f)
filesToUpload.getItems().add(f);
}
});
getChildren().addAll(l, horizSeparator1, filesToUpload, horizSeparator2, chooseFileButton);
}
}
package listview.example.test;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import listview.example.FileUploaderVBox;
public class FileUploaderVBoxTest extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
FileUploaderVBox up = new FileUploaderVBox(primaryStage);
Scene scene = new Scene(up, 400.0, 200.0);
primaryStage.setScene(scene);
primaryStage.show();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The code works if you call ListCell.itemProperty().getValue().toString() instead of ListCell.itemProperty().toString(). That's the commented out code in the example.
If you don't call getValue() you get stack overflow.
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux XPS-15-9560 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
I call ListView.setCellFactory() and call ListCell.textProperty().bind() with a StringBinding. The StringBinding calls ListCell.itemProperty().toString(). Executing this code causes stack overflow
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following example. Select a file from the FileChooser.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
See the selected file in the ListView.
ACTUAL -
StackOverflowError
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package listview.example;
import java.io.File;
import java.util.concurrent.Callable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ObjectProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Separator;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class FileUploaderVBox extends VBox {
ListView<File> filesToUpload = new ListView<>();
public FileUploaderVBox(Stage primaryStage) {
setAlignment(Pos.TOP_CENTER);
Label l = new Label("Select Files to Upload");
l.setStyle("-fx-font: 12 arial; -fx-font-weight: bold;");
setMargin(l, new Insets(25,0,20,0));
Separator horizSeparator1 = new Separator();
horizSeparator1.prefWidthProperty().bind(widthProperty());
filesToUpload.setCellFactory(lv -> {
ListCell<File> cell = new ListCell<>();
ContextMenu contextMenu = new ContextMenu();
MenuItem deleteItem = new MenuItem();
deleteItem.textProperty().bind(Bindings.format("Delete \"%s\"", cell.itemProperty()));
deleteItem.setOnAction(event -> filesToUpload.getItems().remove(cell.getItem()));
contextMenu.getItems().addAll(deleteItem);
// cell.textProperty().bind(cell.itemProperty());
// cell.textProperty().bind(cell.itemProperty().asString());
ObjectProperty<File> itemProperty = cell.itemProperty();
// StringBinding sb = Bindings.createStringBinding(new Callable<String>() {
//
// @Override
// public String call() throws Exception {
//
// if (null == itemProperty.getValue())
// return "";
// else
// return itemProperty.getValue().toString();
// }
//
// }, itemProperty);
StringBinding sb = Bindings.createStringBinding(new Callable<String>() {
@Override
public String call() throws Exception {
if (null == itemProperty)
return "";
else
return itemProperty.toString();
}
}, itemProperty);
cell.textProperty().bind(sb);
cell.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
cell.setContextMenu(null);
} else {
cell.setContextMenu(contextMenu);
}
});
return cell ;
});
Separator horizSeparator2 = new Separator();
horizSeparator2.prefWidthProperty().bind(widthProperty());
Button chooseFileButton = new Button("Choose File");
chooseFileButton.setOnAction(new EventHandler<ActionEvent> () {
@Override
public void handle(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
File f = fileChooser.showOpenDialog(primaryStage);
if (null != f)
filesToUpload.getItems().add(f);
}
});
getChildren().addAll(l, horizSeparator1, filesToUpload, horizSeparator2, chooseFileButton);
}
}
package listview.example.test;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import listview.example.FileUploaderVBox;
public class FileUploaderVBoxTest extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
FileUploaderVBox up = new FileUploaderVBox(primaryStage);
Scene scene = new Scene(up, 400.0, 200.0);
primaryStage.setScene(scene);
primaryStage.show();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The code works if you call ListCell.itemProperty().getValue().toString() instead of ListCell.itemProperty().toString(). That's the commented out code in the example.
If you don't call getValue() you get stack overflow.