private static class ListContentBinding implements ListChangeListener, WeakListener { public static Object bind(List list1, ObservableList list2, Callback converter) { // checkParameters(list1, list2); final ListContentBinding contentBinding = new ListContentBinding<>(list1, converter); if (list1 instanceof ObservableList) { ((ObservableList) list1).setAll(contentBinding.convert(list2)); } else { list1.clear(); list1.addAll(contentBinding.convert(list2)); } list2.addListener(contentBinding); return contentBinding; } private final WeakReference> listRef; private final Callback converter; public ListContentBinding(List list, Callback converter) { this.listRef = new WeakReference<>(list); this.converter = converter; } @Override public void onChanged(ListChangeListener.Change change) { final List list = listRef.get(); if (list == null) { change.getList().removeListener(this); } else { while (change.next()) { if (change.wasPermutated()) { list.subList(change.getFrom(), change.getTo()).clear(); list.addAll(change.getFrom(), convert(change.getList().subList(change.getFrom(), change.getTo()))); } else { if (change.wasRemoved()) { list.subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear(); } if (change.wasAdded()) { list.addAll(change.getFrom(), convert(change.getAddedSubList())); } } } } } @Override public boolean wasGarbageCollected() { return listRef.get() == null; } @Override public int hashCode() { final List list = listRef.get(); return (list == null)? 0 : list.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } final List list1 = listRef.get(); if (list1 == null) { return false; } if (obj instanceof ListContentBinding) { final ListContentBinding other = (ListContentBinding) obj; final List list2 = other.listRef.get(); return list1 == list2; } return false; } private Collection convert(List addedSubList) { List res = new ArrayList<>(addedSubList.size()); for (EF elem : addedSubList) { res.add(converter.call(elem)); } return res; } }