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