-
Bug
-
Resolution: Fixed
-
P3
-
8
-
Windows 7 64bit, JDK 1.8.0_5 64bit, JavaFX 8_5 64bit, NetBeans 8 64bit
The chart class StackedAreaChart does not test if a series is empty in its layoutPlotChildren() code. This provokes an IndexOutOfBoundsException at runtime.
The following code creates a StackedAreaChart and attaches an empty series to it:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
final StackedAreaChart<Long, Integer> chart = new StackedAreaChart(new NumberAxis(0, 10, 2), new NumberAxis(0, 10, 2));
final StackedAreaChart.Series<Long, Integer> series = new StackedAreaChart.Series();
series.setName("Test");
chart.getData().add(series);
StackPane root = new StackPane();
root.getChildren().add(chart);
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Stack Area Chart - Empty Series");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
We do so because we are populating the chart with a timer so the series starts initially as being devoided of data.
At runtime this code immediately raises:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:367)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:305)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:894)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:56)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:158)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:638)
at java.util.ArrayList.get(ArrayList.java:414)
at javafx.scene.chart.StackedAreaChart.layoutPlotChildren(StackedAreaChart.java:644)
at javafx.scene.chart.XYChart.layoutChartChildren(XYChart.java:736)
at javafx.scene.chart.Chart$1.layoutChildren(Chart.java:87)
at javafx.scene.Parent.layout(Parent.java:1076)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Scene.doLayoutPass(Scene.java:576)
at javafx.scene.Scene.preferredSize(Scene.java:1579)
at javafx.scene.Scene.impl_preferredSize(Scene.java:1653)
at javafx.stage.Window$9.invalidated(Window.java:750)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
at javafx.stage.Window.setShowing(Window.java:826)
at javafx.stage.Window.show(Window.java:841)
at javafx.stage.Stage.show(Stage.java:247)
at test.Main.start(Main.java:32)
at com.sun.javafx.application.LauncherImpl$8.run(LauncherImpl.java:837)
at com.sun.javafx.application.PlatformImpl$7.run(PlatformImpl.java:335)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
... 1 more
Exception running application test.Main
Java Result: 1
Inspection of the source code for StackedAreaChart at line 644 shows that the layoutPlotChildren() method for this class does not check if the series is empty before attempting to access the very first data in the series. The methods acts as follows:
seriesLine.getElements().add(new MoveTo(currentSeriesData.get(0).displayX, currentSeriesData.get(0).displayY));
fillPath.getElements().add(new MoveTo(currentSeriesData.get(0).displayX, currentSeriesData.get(0).displayY));
for (DataPointInfo point : currentSeriesData) {
[...]
Data from the series are converted to dataPointInfo objects and stored into the currentSeriesData object, a list. So this list is empty if the series is empty.
It is quite obvious that the code should test first if the currentSeriesData list is empty before doing the very first moveTo...
The following code creates a StackedAreaChart and attaches an empty series to it:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
final StackedAreaChart<Long, Integer> chart = new StackedAreaChart(new NumberAxis(0, 10, 2), new NumberAxis(0, 10, 2));
final StackedAreaChart.Series<Long, Integer> series = new StackedAreaChart.Series();
series.setName("Test");
chart.getData().add(series);
StackPane root = new StackPane();
root.getChildren().add(chart);
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Stack Area Chart - Empty Series");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
We do so because we are populating the chart with a timer so the series starts initially as being devoided of data.
At runtime this code immediately raises:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:367)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:305)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:894)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:56)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:158)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:638)
at java.util.ArrayList.get(ArrayList.java:414)
at javafx.scene.chart.StackedAreaChart.layoutPlotChildren(StackedAreaChart.java:644)
at javafx.scene.chart.XYChart.layoutChartChildren(XYChart.java:736)
at javafx.scene.chart.Chart$1.layoutChildren(Chart.java:87)
at javafx.scene.Parent.layout(Parent.java:1076)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Scene.doLayoutPass(Scene.java:576)
at javafx.scene.Scene.preferredSize(Scene.java:1579)
at javafx.scene.Scene.impl_preferredSize(Scene.java:1653)
at javafx.stage.Window$9.invalidated(Window.java:750)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
at javafx.stage.Window.setShowing(Window.java:826)
at javafx.stage.Window.show(Window.java:841)
at javafx.stage.Stage.show(Stage.java:247)
at test.Main.start(Main.java:32)
at com.sun.javafx.application.LauncherImpl$8.run(LauncherImpl.java:837)
at com.sun.javafx.application.PlatformImpl$7.run(PlatformImpl.java:335)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
... 1 more
Exception running application test.Main
Java Result: 1
Inspection of the source code for StackedAreaChart at line 644 shows that the layoutPlotChildren() method for this class does not check if the series is empty before attempting to access the very first data in the series. The methods acts as follows:
seriesLine.getElements().add(new MoveTo(currentSeriesData.get(0).displayX, currentSeriesData.get(0).displayY));
fillPath.getElements().add(new MoveTo(currentSeriesData.get(0).displayX, currentSeriesData.get(0).displayY));
for (DataPointInfo point : currentSeriesData) {
[...]
Data from the series are converted to dataPointInfo objects and stored into the currentSeriesData object, a list. So this list is empty if the series is empty.
It is quite obvious that the code should test first if the currentSeriesData list is empty before doing the very first moveTo...