Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8097350

[StackedAreaChart] does not test for empty series causing AIOOBE

XMLWordPrintable

      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...

            msladecek Martin Sládeček
            fbouyajfx Fabrice Bouyé (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: