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 ObservableList
s. 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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With