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

FilteredList throws ArrayIndexOutOfBoundsException on ListChangeEvent with multiple change

    XMLWordPrintable

Details

    • generic
    • generic

    Description

      FULL PRODUCT VERSION :
      java version "1.8.0_152"
      Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
      Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [version 10.0.16299.192]

      A DESCRIPTION OF THE PROBLEM :
      FilteredList throw ArrayIndexOutOfBoundsException arbitrarily when a change event contains both remove and added elements and when list size is increasing


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached test case


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      ant -f C:\\Users\\daniel\\dev\\JavaSamples -Djavac.includes=bugFilteredList/bugFilteredList.java -Dnb.internal.action.name=run.single -Drun.class=bugFilteredList.bugFilteredList run-single
      init:
      Deleting: C:\Users\daniel\dev\JavaSamples\build\built-jar.properties
      deps-jar:
      Updating property file: C:\Users\daniel\dev\JavaSamples\build\built-jar.properties
      Compiling 1 source file to C:\Users\daniel\dev\JavaSamples\build\classes
      compile-single:
      run-single:
      trying to move index 2 after 0 in a list of 3 elements
      elements = a0,a1,a2
      elements = a0,a2,a1
      trying to move index 2 after 0 in a list of 4 elements
      elements = a0,a1,a2,a3
      elements = a0,a2,a1,a3
      trying to move index 2 after 0 in a list of 5 elements
      elements = a0,a1,a2,a3,a4
      elements = a0,a2,a1,a3,a4
      trying to move index 2 after 0 in a list of 6 elements
      elements = a0,a1,a2,a3,a4,a5
      elements = a0,a2,a1,a3,a4,a5
      trying to move index 2 after 0 in a list of 7 elements
      elements = a0,a1,a2,a3,a4,a5,a6
      elements = a0,a2,a1,a3,a4,a5,a6
      trying to move index 2 after 0 in a list of 8 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7
      elements = a0,a2,a1,a3,a4,a5,a6,a7
      trying to move index 2 after 0 in a list of 9 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8
      trying to move index 2 after 0 in a list of 10 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9
      trying to move index 2 after 0 in a list of 11 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10
      trying to move index 2 after 0 in a list of 12 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11
      trying to move index 2 after 0 in a list of 13 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12
      trying to move index 2 after 0 in a list of 14 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13
      trying to move index 2 after 0 in a list of 15 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14
      trying to move index 2 after 0 in a list of 16 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
      trying to move index 2 after 0 in a list of 17 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16
      trying to move index 2 after 0 in a list of 18 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17
      trying to move index 2 after 0 in a list of 19 elements
      elements = a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18
      elements = a0,a2,a1,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18
      BUILD SUCCESSFUL (total time: 0 seconds)

      ACTUAL -
      ant -f C:\\Users\\daniel\\dev\\JavaSamples -Djavac.includes=bugFilteredList/bugFilteredList.java -Dnb.internal.action.name=run.single -Drun.class=bugFilteredList.bugFilteredList run-single
      init:
      Deleting: C:\Users\daniel\dev\JavaSamples\build\built-jar.properties
      deps-jar:
      Updating property file: C:\Users\daniel\dev\JavaSamples\build\built-jar.properties
      Compiling 1 source file to C:\Users\daniel\dev\JavaSamples\build\classes
      compile-single:
      run-single:
      trying to move index 2 after 0 in a list of 3 elements
      elements = a0,a1,a2
      elements = a0,a2,a1
      trying to move index 2 after 0 in a list of 4 elements
      elements = a0,a1,a2,a3
      Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
      at java.lang.System.arraycopy(Native Method)
      at javafx.collections.transformation.FilteredList.addRemove(FilteredList.java:269)
      at javafx.collections.transformation.FilteredList.sourceChanged(FilteredList.java:144)
      at javafx.collections.transformation.TransformationList.lambda$getListener$23(TransformationList.java:106)
      at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
      at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
      at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
      at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
      at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:524)
      at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
      at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
      at bugFilteredList.bugFilteredList$MyList.removeAndAdd(bugFilteredList.java:61)
      at bugFilteredList.bugFilteredList.test1(bugFilteredList.java:95)
      at bugFilteredList.bugFilteredList.main(bugFilteredList.java:79)
      Exception in thread "main" java.util.NoSuchElementException
      at java.util.AbstractList$Itr.next(AbstractList.java:364)
      at java.util.Iterator.forEachRemaining(Iterator.java:116)
      at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
      at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
      at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
      at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
      at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
      at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
      at bugFilteredList.bugFilteredList.test1(bugFilteredList.java:96)
      at bugFilteredList.bugFilteredList.main(bugFilteredList.java:79)
      Java Result: 1
      BUILD SUCCESSFUL (total time: 0 seconds)


      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
      at java.lang.System.arraycopy(Native Method)
      at javafx.collections.transformation.FilteredList.addRemove(FilteredList.java:269)
      at javafx.collections.transformation.FilteredList.sourceChanged(FilteredList.java:144)
      at javafx.collections.transformation.TransformationList.lambda$getListener$23(TransformationList.java:106)
      at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
      at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
      at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
      at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
      at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:524)
      at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
      at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
      at bugFilteredList.bugFilteredList$MyList.removeAndAdd(bugFilteredList.java:61)
      at bugFilteredList.bugFilteredList.test1(bugFilteredList.java:95)
      at bugFilteredList.bugFilteredList.main(bugFilteredList.java:79)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      /*
       * To change this license header, choose License Headers in Project Properties.
       * To change this template file, choose Tools | Templates
       * and open the template in the editor.
       */
      package bugFilteredList;

      import java.util.ArrayList;
      import java.util.List;
      import java.util.stream.Collectors;
      import javafx.collections.ModifiableObservableListBase;
      import javafx.collections.transformation.FilteredList;

      /**
       *
       * @author daniel
       */
      public class bugFilteredList {

          public static class MyList<Model> extends ModifiableObservableListBase<Model> {

              private final List<Model> children = new ArrayList<>();

              @Override
              public Model get(int index) {
                  return children.get(index);
              }

              @Override
              public int size() {
                  return children.size();
              }

              @Override
              protected void doAdd(int index, Model element) {

                  children.add(index, element);
              }

              @Override
              protected Model doSet(int index, Model element) {
                  if (children.get(index) == element) {
                      return element;
                  } else {
                      Model old = children.set(index, element);
                      return old;
                  }
              }

              @Override
              protected Model doRemove(int index) {
                  Model child = children.remove(index);
                  return child;
              }

              public void removeAndAdd(Model o, Model after) {
                  beginChange();
                  remove(o);
                  int index = after == null ? 0 : indexOf(after) + 1;
                  add(index, o);
                  endChange();
              }

              public void permute(Model o, Model after) {
                  beginChange();
                  int idxToRemove = indexOf(o);
                  int indexToAdd = after == null ? 0 : indexOf(after) + 1;
                  idxToRemove = idxToRemove > indexToAdd ? idxToRemove + 1 : idxToRemove;
                  children.add(indexToAdd, o);
                  children.remove(idxToRemove);
      // nextAdd(indexToAdd, indexToAdd + 1);
      // nextRemove(idxToRemove, o);
                  nextPermutation(idxToRemove, idxToRemove + 1, new int[]{indexToAdd});
                  endChange();
              }
          }

          public static void main(String[] args) {
              test1();
          }

          private static void test1() {

              for (int j = 3; j < 20; j++) {
                  System.err.println("trying to move index 2 after 0 in a list of " + j + " elements");
                  MyList<String> observableList = new MyList<>();
                  FilteredList<String> filteredList = new FilteredList<>(observableList);

                  for (int i = 0; i < j; i++) {
                      final String a = "a" + i;
                      observableList.add(a);
                  }

                  System.out.println("elements = " + filteredList.stream().collect(Collectors.joining(",")));
                  observableList.removeAndAdd(observableList.get(2), observableList.get(0));
                  System.out.println("elements = " + filteredList.stream().collect(Collectors.joining(",")));

              }
          }

          private static void test2() {
              for (int j = 100; j > 0; j--) {
                  MyList<String> observableList = new MyList<>();
                  System.err.println("observable list with " + j + " elements");
                  for (int i = 0; i < j; i++) {
                      final String a = "a" + i;
                      observableList.add(a);
                  }

                  FilteredList<String> filteredList = new FilteredList<>(observableList);
                  final String b = "b";
                  observableList.add(b);
      // System.out.println("elements = " + filteredList.stream().collect(Collectors.joining(",")));
                  observableList.removeAndAdd(b, null);
      // System.out.println("elements = " + filteredList.stream().collect(Collectors.joining(",")));
              }

          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No, excepts copying FileterdList source code and fixing it.

      I've trying the following fix which seems to work in FilteredList:
      @@ -237,7 +237,7 @@

           private void addRemove(Change<? extends E> c) {
               Predicate<? super E> pred = getPredicateImpl();
      - ensureSize(getSource().size());
      + ensureSize(getSource().size() + c.getAddedSize());
               final int from = findPosition(c.getFrom());
               final int to = findPosition(c.getFrom() + c.getRemovedSize());


      Attachments

        Issue Links

          Activity

            People

              kcr Kevin Rushforth
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated: