FilteredList gives java.lang.ArrayIndexOutOfBoundsException when updating

I created a simple application for testing filtered lists and their behavior when changing the corresponding list of sources. I would also like to test update changes, so I created an ObservableList from ObservableList s. This is faster and easier than creating an additional class, such as Person, which has observable fields.

The code looks like this:

  ListChangeListener<ObservableList<String>> changeNotifier = new ListChangeListener<ObservableList<String>>() { @Override public void onChanged(Change<? extends ObservableList<String>> c) { while (c.next()) { if (c.wasPermutated()) { System.out.println("permutation"); } else if (c.wasUpdated()) { System.out.println("update"); } else { if (c.wasRemoved()) { System.out.println("remove"); } if (c.wasAdded()) { System.out.println("add"); } if (c.wasReplaced()) { System.out.println("replace"); } } } } }; Callback<ObservableList<String>, Observable[]> identityExtractor = new Callback<ObservableList<String>, Observable[]>() { @Override public Observable[] call(ObservableList<String> param) { return new Observable[]{param}; } }; Predicate<ObservableList<String>> nonEmptyFilter = new Predicate<ObservableList<String>>() { @Override public boolean test(ObservableList<String> obsl) { boolean nonEmpty = ! obsl.isEmpty(); for (String item : obsl) { nonEmpty = nonEmpty && (null != item) && ("" != item); }; return nonEmpty; } }; ObservableList<ObservableList<String>> basicSimple = FXCollections.observableArrayList(); ObservableList<ObservableList<String>> basicComposed = FXCollections.observableArrayList( identityExtractor ); ObservableList<ObservableList<String>> filteredSimple = basicSimple.filtered( nonEmptyFilter ); ObservableList<ObservableList<String>> filteredComposed = basicComposed.filtered( nonEmptyFilter ); System.out.println("Basic testing"); System.out.println("Add invalid"); basicSimple.addAll( FXCollections.observableArrayList("") ); System.out.println( basicSimple ); System.out.println( filteredSimple ); System.out.println("Make it valid"); basicSimple.get(0).addAll("first"); System.out.println( filteredSimple ); System.out.println("Add valid"); basicSimple.addAll( FXCollections.observableArrayList("Second") ); System.out.println( filteredSimple ); System.out.println("Composed testing"); System.out.println("Add invalid"); basicComposed.addAll( FXCollections.observableArrayList("") ); System.out.println( basicComposed ); System.out.println( filteredComposed ); System.out.println("Make it valid"); basicComposed.get(0).addAll("first"); System.out.println( filteredComposed ); System.out.println("Add valid"); basicComposed.addAll( FXCollections.observableArrayList("Second") ); System.out.println( filteredComposed ); 

I found a strange error during testing:

 [info] Running helloworld.HelloWorld Basic testing Add invalid [[]] [] Make it valid [] Add valid [[Second]] Composed testing Add invalid [[]] [] Make it valid [error] (JavaFX Application Thread) java.lang.ArrayIndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException at java.lang.System.arraycopy(Native Method) at javafx.collections.transformation.FilteredList.updateFilter(FilteredList.java:298) at javafx.collections.transformation.FilteredList.update(FilteredList.java:239) at javafx.collections.transformation.FilteredList.sourceChanged(FilteredList.java:137) at javafx.collections.transformation.TransformationList.lambda$getListener$16(TransformationList.java:106) at javafx.collections.transformation.TransformationList$$Lambda$63/1596532574.onChanged(Unknown Source) 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:485) at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541) at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205) at com.sun.javafx.collections.ObservableListWrapper.access$200(ObservableListWrapper.java:45) at com.sun.javafx.collections.ObservableListWrapper$1$1.invalidated(ObservableListWrapper.java:75) at com.sun.javafx.collections.ListListenerHelper$SingleInvalidation.fireValueChangedEvent(ListListenerHelper.java:126) 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:482) at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541) at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205) at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:102) at javafx.collections.ObservableListBase.addAll(ObservableListBase.java:245) at helloworld.HelloWorld.start(HelloWorld.java:87) at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821) at com.sun.javafx.application.LauncherImpl$$Lambda$55/7143454.run(Unknown Source) at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323) at com.sun.javafx.application.PlatformImpl$$Lambda$51/397137382.run(Unknown Source) at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292) at com.sun.javafx.application.PlatformImpl$$Lambda$53/1802784360.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291) at com.sun.javafx.application.PlatformImpl$$Lambda$52/1184782272.run(Unknown Source) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) at com.sun.glass.ui.gtk.GtkApplication.lambda$null$45(GtkApplication.java:126) at com.sun.glass.ui.gtk.GtkApplication$$Lambda$43/450111611.run(Unknown Source) at java.lang.Thread.run(Thread.java:745) [trace] Stack trace suppressed: run last compile:run for the full output. [] Add valid [[Second]] 

The difference between basicSimple and basicComposed is that the latter has a qualifier, so it receives update events. In the middle of processing the update event, an exception was thrown by native code. What should I consider for a sample code to work without errors?


Debug bit

I inserted println at the end of the nonEmptyFilter predicate nonEmptyFilter . It works correctly, and the ObservableList is passed to it, as expected, a new value that was just updated. The error occurs later when some iterative FilteredList code is executed.

+5
source share
2 answers

It looks like an error; I think this is probably the same as the one reported in the bug report, fixed for JavaFX 8u60 (supposedly too late for 8u40).

I tested on 1.8.0_40-ea-b23 ?? and 1.9.0-ea-b49, and an error appeared in both versions. If there is currently version 1.8.0u60, I'm not sure where to find it.

+5
source

Thus, the exception is thrown by the line basicComposed.get(0).addAll("first"); but intuitively intrigues her not get(0) , which throws an exception, but addAll !?

Another interesting thing is that if you remove identityExtractor , will the exception go away? In addition, an exception is raised only when nonEmptyFilter returns false!

So, there is some kind of dynamic between identityExtractor and nonEmptyFilter that causes addAll throw an exception.

You can change the current situation so that the exception is only if both of the following two conditions are true:

  • basicComposed.get(0).isEmpty() and
  • basicComposed.get(0).addAll("") // add an empty string
0
source

Source: https://habr.com/ru/post/1213023/


All Articles