FilteredList gives java.lang.ArrayIndexOutOfBoundsException on update

烂漫一生 提交于 2019-12-23 09:59:33

问题


I created a simple application to test filtered lists and their behavior when the corresponding source list changes. I'd like to test update changes also, so I created ObservableList of ObservableLists. It is faster and simpler than creating additional class like Person that have observable fields.

The code looks so:

    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've discovered 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 latter have an extractor defined, so it receives update events. In the middle of processing update event the exception was thrown by a native code. What should I consider to make the sample code work without errors?


Bit of debugging

I've inserted println to the end of the nonEmptyFilter predicate test. It works correctly and the ObservableList passed to it is as expected new value that was just updated. The error occurs later when some iternal code of FilteredList is executing.


回答1:


This looks like a bug; I think it is probably the same as this one, which the bug report says is fixed for JavaFX 8u60 (presumably too late for 8u40).

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




回答2:


So the exception gets thrown by the line basicComposed.get(0).addAll("first"); but counter intuitively its not get(0) that's throwing the exception but addAll !?

Another thing of interest is that if you remove the identityExtractor then the exception goes away ? In addition the exception is only ever thrown if nonEmptyFilter returns false !

So there's some kind of dynamic between the identityExtractor and nonEmptyFilter that causes addAll to throw the exception.

It's possible to change the current situation so that the exception is only thrown if both the following two conditions hold true:

  1. basicComposed.get(0).isEmpty() and
  2. basicComposed.get(0).addAll("") // adding an empty string


来源:https://stackoverflow.com/questions/28424864/filteredlist-gives-java-lang-arrayindexoutofboundsexception-on-update

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!