Equivalent of C# ObservableCollection in Java - java

I was wondering if there is a data structure that acts like an OberservableCollection almost like in C# that is able to take a certain type.
ex:
In C# i am able to say..
ObservableCollection<Beer> Beer = new ObservableCollection<Beer>();
Beer.add("Bud"); <br>
Beer.add("Coors");
Assuming that the class Beer is made and we can change the alcohol content so that
Beer[1].content = 5;
I was wondering if anyone knows if there is such a data structure/s that work as well with Java.
I am a C# programmer, not much of a Java programmer so just wondering. Also, it has to be able to take in a custom type, not generic.

org.apache.commons.events.observable
Class ObservableCollection

Observable data structures (ObservableList, ObservableMap, etc) are included in Oracle Java 7u6+ as part of the JavaFX project. A corresponding library for OpenJDK is provided by the OpenJFX project.
Here is a tutorial on using JavaFX collections.
And some sample code for using a JavaFX observable list from the linked tutorial:
import java.util.List;
import java.util.ArrayList;
import javafx.collections.*;
public class CollectionsDemo {
public static void main(String[] args) {
// Use Java Collections to create the List.
List<String> list = new ArrayList<String>();
// Now add observability by wrapping it with ObservableList.
ObservableList<String> observableList = FXCollections.observableList(list);
observableList.addListener(new ListChangeListener() {
#Override public void onChanged(ListChangeListener.Change change) {
System.out.println("Detected a change! ");
}
});
// Changes to the observableList WILL be reported.
// This line will print out "Detected a change!"
observableList.add("item one");
// Changes to the underlying list will NOT be reported
// Nothing will be printed as a result of the next line.
list.add("item two");
System.out.println("Size: "+observableList.size());
}
}

If you want to Observe your lists, i.e. be notified when list changes, you can use Glazed Lists.
If you just want to modify objects stored in your lists, you can get your objects by using List.get(int index), or by iterating the list.
If you want to automatically create Beer objects when storing Strings into the list, you'll probably need to write your own simple list wrapper.

JavaFX now has ObservableList that match your needs, in the case that you don't want to depend on JavaFX - here is a class that I wrote a while ago that can be used instead.
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
/**
*
* #author bennyl
*/
public class ObservableList<T> implements List<T> {
private List<T> wrapped;
private LinkedList<Listener<T>> listeners = new LinkedList<>();
public ObservableList(List wrapped) {
this.wrapped = wrapped;
}
public void addListener(Listener l) {
listeners.add(l);
}
public void removeListener(Listener l) {
listeners.remove(l);
}
#Override
public int size() {
return wrapped.size();
}
#Override
public boolean isEmpty() {
return wrapped.isEmpty();
}
#Override
public boolean contains(Object o) {
return wrapped.contains(o);
}
#Override
public Iterator<T> iterator() {
final Iterator<T> iterator = wrapped.iterator();
return new Iterator<T>() {
T current = null;
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public T next() {
return current = iterator.next();
}
#Override
public void remove() {
iterator.remove();
fireRemoved(current);
}
};
}
private void fireRemoved(T... items) {
fireRemoved(Arrays.asList(items));
}
#Override
public Object[] toArray() {
return wrapped.toArray();
}
#Override
public <T> T[] toArray(T[] a) {
return wrapped.toArray(a);
}
#Override
public boolean add(T e) {
if (wrapped.add(e)) {
fireAdded(e);
return true;
} else {
return false;
}
}
#Override
public boolean remove(Object o) {
if (wrapped.remove(o)) {
fireRemoved((T) o);
return true;
}
return false;
}
#Override
public boolean containsAll(Collection<?> c) {
return wrapped.containsAll(c);
}
#Override
public boolean addAll(Collection<? extends T> c) {
if (wrapped.addAll(c)) {
fireAdded(c);
return true;
}
return false;
}
#Override
public boolean addAll(int index, Collection<? extends T> c) {
if (wrapped.addAll(index, c)) {
fireAdded(c);
}
return false;
}
#Override
public boolean removeAll(Collection<?> c) {
if (wrapped.removeAll(c)) {
fireRemoved((Collection<? extends T>) c);
return true;
}
return false;
}
#Override
public boolean retainAll(Collection<?> c) {
if (wrapped.retainAll(c)) {
fireStracturalChange();
}
return false;
}
#Override
public void clear() {
wrapped.clear();
fireStracturalChange();
}
#Override
public boolean equals(Object o) {
return wrapped.equals(o);
}
#Override
public int hashCode() {
return wrapped.hashCode();
}
#Override
public T get(int index) {
return wrapped.get(index);
}
#Override
public T set(int index, T element) {
T old = wrapped.set(index, element);
fireRemoved(old);
fireAdded(element);
return old;
}
#Override
public void add(int index, T element) {
wrapped.add(index, element);
fireAdded(element);
}
#Override
public T remove(int index) {
T old = wrapped.remove(index);
fireRemoved(old);
return old;
}
#Override
public int indexOf(Object o) {
return wrapped.indexOf(o);
}
#Override
public int lastIndexOf(Object o) {
return wrapped.lastIndexOf(o);
}
#Override
public ListIterator<T> listIterator() {
return wrapped.listIterator();
}
#Override
public ListIterator<T> listIterator(int index) {
return wrapped.listIterator(index);
}
#Override
public List<T> subList(int fromIndex, int toIndex) {
return wrapped.subList(fromIndex, toIndex);
}
private void fireRemoved(Collection<? extends T> asList) {
for (Listener<T> l : listeners) {
l.onItemsRemoved(this, asList);
}
}
private void fireAdded(T... e) {
fireAdded(Arrays.asList(e));
}
private void fireAdded(Collection<? extends T> asList) {
for (Listener<T> l : listeners) {
l.onItemsAdded(this, asList);
}
}
private void fireStracturalChange() {
for (Listener<T> l : listeners) {
l.onStracturalChange(this);
}
}
public static interface Listener<T> {
void onItemsAdded(ObservableList<T> source, Collection<? extends T> items);
void onItemsRemoved(ObservableList<T> source, Collection<? extends T> items);
void onStracturalChange(ObservableList<T> source);
}
}

There isn't at least in Java Collections api
http://download-llnw.oracle.com/javase/1.5.0/docs/guide/collections/designfaq.html#27
You can create an wrapper or proxy

You can consider using the java.util.Observable class, here is an example :
public class Try extends Observable{
private static List<String> list = new ArrayList<String>();
private static Try observableObj = new Try();
public static List<String> getList(){
observableObj.setChanged();
observableObj.notifyObservers();
return list;
}
public static void main(String[] args) throws RemoteException {
Try2 observer1 = new Try2();
Try2 observer2 = new Try2();
observableObj.addObserver(observer1);
observableObj.addObserver(observer2);
System.out.println(getList().isEmpty());
}
}
class Try2 implements Observer{
#Override
public void update(Observable arg0, Object arg1) {
System.out.println(this.toString()+" has been notified");
}
}
In this way every time the ArrayList gets accessed the two observers get notified.

Sure, you can do this. If you had a class called Soda, you could do:
List<Soda> sodas = new ArrayList<Soda>();
sodas.add(new Soda("Coke"));
sodas.add(new Soda("Sprite"));
Then you could do
sodas.get(1).setSugar(255);

Related

void with Generics in Java

I have a function that returns void
public interface IProductService {
void delete(String id);
}
Generic method
public interface IRequestHandler<C , R> {
R handler(C c);
Class<C> commandType();
}
Implementation of generic interface
#Singleton
public record DeleteProductCommandHandler(IProductService iProductService)
implements IRequestHandler<DeleteProductCommand, Void> {
#Override
public Void handler(DeleteProductCommand deleteProductCommand) {
return iProductService.delete(deleteProductCommand.id);
}
#Override
public Class<DeleteProductCommand> commandType() {
return DeleteProductCommand.class;
}
}
How can I use void in IRequestHandler<DeleteProductCommand, Void> so that I can map void from iProductService.delete(deleteProductCommand.id);
Option 1:
Just return null:
#Override
public Void handler(DeleteProductCommand deleteProductCommand) {
iProductService.delete(deleteProductCommand.id);
return null;
}
Option 2:
Update the IProductService::delete method to return something meaningful, e.g. a boolean value like Collection::remove does:
public interface IProductService {
boolean delete(String id);
}
#Singleton
public record DeleteProductCommandHandler(IProductService iProductService)
implements IRequestHandler<DeleteProductCommand, Boolean> {
#Override
public Boolean handler(DeleteProductCommand deleteProductCommand) {
return iProductService.delete(deleteProductCommand.id);
}
#Override
public Class<DeleteProductCommand> commandType() {
return DeleteProductCommand.class;
}
}

Best way to serialize composite - (design pattern)

I have following java code that is implementation of Composite Design pattern:
//composite designed for type safety (all Leaf-only operations only in leaf)
interface Component extends Visitable {
void enable();
void disable();
}
class CompositeA implements Component {
private String compositeData;
private boolean enabled;
private Set<Component> components = new HashSet<>();
CompositeA(String compositeData) {
this.compositeData = compositeData;
}
void addChild(Component component){
this.components.add(component);
}
String getCompositeData() {
return compositeData;
}
Set<Component> getComponents() {
return components;
}
#Override
public void enable() {
this.enabled = true;
}
#Override
public void disable() {
this.enabled = false;
}
#Override
public Object accept(ComponentVisitor visitor) {
return visitor.visit(this);
}
}
class CompositeB implements Component{
private int compositeData;
private boolean enabled;
private Set<Component> components = new HashSet<>();
CompositeB(int compositeData) {
this.compositeData = compositeData;
}
void addChild(Component component){
this.components.add(component);
}
int getCompositeData() {
return compositeData;
}
Set<Component> getComponents() {
return components;
}
#Override
public void enable() {
this.enabled = true;
}
#Override
public void disable() {
this.enabled = false;
}
#Override
public Object accept(ComponentVisitor visitor) {
return visitor.visit(this);
}
}
class Leaf implements Component {
private boolean enabled;
private String[] leafData;
Leaf(String[] leafData) {
this.leafData = leafData;
}
String[] getLeafData() {
return leafData;
}
#Override
public void enable() {
this.enabled = true;
}
#Override
public void disable() {
this.enabled = false;
}
#Override
public Object accept(ComponentVisitor visitor) {
return visitor.visit(this);
}
}
There are 2 possible composite roots here (CompositeA and CompositeB) and one leaf component (Leaf).
Here I define DTOs that will hold serialized data:
class WholeCompositeASerialized {
String content;
List<Object> serializedChildren;
}
class WholeCompositeBSerialized{
String content;
List<Object> serializedChildren;
}
class WholeLeafSerialized{
String content;
}
Now if I use visitor pattern for serialization, I get something like this:
interface ComponentVisitor {
WholeCompositeASerialized visit(CompositeA compositeA);
WholeCompositeBSerialized visit(CompositeB compositeB);
WholeLeafSerialized visit(Leaf leaf);
}
class SerializableComponentVisitor implements ComponentVisitor{
#Override
public WholeCompositeASerialized visit(CompositeA compositeA) {
WholeCompositeASerialized wcas = new WholeCompositeASerialized();
wcas.serializedChildren = compositeA
.getComponents()
.stream()
.map(c -> c.accept(this))
.collect(Collectors.toList());
wcas.content = compositeA.getCompositeData();
return wcas;
}
#Override
public WholeCompositeBSerialized visit(CompositeB compositeB) {
WholeCompositeBSerialized wcbs = new WholeCompositeBSerialized();
wcbs.serializedChildren = compositeB
.getComponents()
.stream()
.map(c -> c.accept(this))
.collect(Collectors.toList());
wcbs.content = String.valueOf(compositeB.getCompositeData());
return wcbs;
}
#Override
public WholeLeafSerialized visit(Leaf leaf) {
WholeLeafSerialized wls = new WholeLeafSerialized();
wls.content = Arrays.toString(leaf.getLeafData());
return wls;
}
}
interface Visitable{
Object accept(ComponentVisitor visitor);
}
and if I use instanceof this is the code that does the same thing:
class SerializerUsingInstanceOf {
Object decide(Component component){
if(component instanceof CompositeA){
return serialize((CompositeA)component);
}
else if(component instanceof CompositeB){
return serialize((CompositeB)component);
}
else{
return serialize((Leaf)component);
}
}
WholeCompositeASerialized serialize(CompositeA compositeA) {
WholeCompositeASerialized wcas = new WholeCompositeASerialized();
wcas.serializedChildren = compositeA
.getComponents()
.stream()
.map(this::decide)
.collect(Collectors.toList());
wcas.content = compositeA.getCompositeData();
return wcas;
}
WholeCompositeBSerialized serialize(CompositeB compositeB) {
WholeCompositeBSerialized wcbs = new WholeCompositeBSerialized();
wcbs.serializedChildren = compositeB
.getComponents()
.stream()
.map(this::decide)
.collect(Collectors.toList());
wcbs.content = String.valueOf(compositeB.getCompositeData());
return wcbs;
}
WholeLeafSerialized serialize(Leaf leaf) {
WholeLeafSerialized wls = new WholeLeafSerialized();
wls.content = Arrays.toString(leaf.getLeafData());
return wls;
}
}
I guess also that visitor is preferred here because when we add new Component, we are required to implement Object accept(ComponentVisitor visitor) method also - so we cannot forget that we need a code for serialization of this new component. If we do the same when we use instanceof we would possibly forget to add it to that check.
Now - my question is - is there any way that we can get rid of that ugly Object return type in Object accept(ComponentVisitor visitor) method signature? The only other option that comes to my mind is to use some marker interface (eg. interface SerializedComponent {}) and then have all serializer classes implement that empty interface like this class WholeCompositeASerialized implements SerializedComponent but it still does not seem right.
I think the proper way could be to use generics here.
e.g. https://onlinegdb.com/r1m5Eg4DP
public class Main {
public static void main(String []args){
ComponentVisitor<SerializedComponent> serializer = new ComponentSerializer();
Component componentA = new ComponentA();
SerializedComponent serializedA = componentA.accept(serializer);
System.out.println(serializedA);
Component component = new ComponentB();
SerializedComponent serializedB = component.accept(serializer);
System.out.println(serializedB);
}
static interface Component {
public <V> V accept(ComponentVisitor<V> visitor);
}
static class ComponentA implements Component {
public <V> V accept(ComponentVisitor<V> visitor) {
return visitor.visit(this);
}
}
static class ComponentB implements Component {
public <V> V accept(ComponentVisitor<V> visitor) {
return visitor.visit(this);
}
}
static interface SerializedComponent {}
static class SerializedComponentA implements SerializedComponent {
}
static class SerializedComponentB implements SerializedComponent {
}
static interface ComponentVisitor<V> {
public V visit(ComponentA component);
public V visit(ComponentB component);
}
static class ComponentSerializer implements ComponentVisitor<SerializedComponent> {
public SerializedComponent visit(ComponentA component) {
return new SerializedComponentA();
}
public SerializedComponent visit(ComponentB component) {
return new SerializedComponentB();
}
}
}
You are attempting to return concrete type information from the Visitor. This is not the purpose of the pattern. The Visitor encapsulates (and handles) the concrete type internally.
The solution here is to move all logic specific to ComponentA (or any A-specific type you might convert it to) into the visit(ComponentA) method, and likewise for ComponentB.
If you don't want the type encapsulation of the Visitor, then a different design is more suitable, such as pattern matching.
Comments on the comment...
public static void main(String[] args) {
// Using a concrete type here defeats the purpose of these patterns.
// Instead, program to an interface:
// Component c1 = new CompositeA("root");
CompositeA c1 = new CompositeA("root");
c1.addChild(new Leaf(new String[]{"leaf11", "leaf12"}));
CompositeA c2 = new CompositeA("composite1");
c2.addChild(new Leaf(new String[]{"leaf21", "leaf22"}));
c1.addChild(c2);
SerializableComponentVisitor scv = new SerializableComponentVisitor();
// Clients never invoke visit methods directly,
// because they do not have the type information to make these calls.
// A client would execute, c1.accept(scv)
WholeCompositeASerialized wcas1 = scv.visit(c1);
}

How to implement and fire an event when a change occurs in a property of `T` in `List<T>` within the owning class in Java

Any clue if it is possible to convert code below to Java (Android) from C#?
It is based on my prev.question
How to implement and fire an event when a change occurs in a property of `T` in `List<T>` within the owning class
public class ItemPropertyChangedNotifyingList<T> : IList<T>, INotifyPropertyChanged where T : INotifyPropertyChanged
{
private List<T> _listImplementation = new List<T>();
public void Add(T item)
{
item.PropertyChanged += ItemOnPropertyChanged;
_listImplementation.Add(item);
}
private void ItemOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(sender, e);
}
public IEnumerator<T> GetEnumerator()
{
return _listImplementation.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_listImplementation).GetEnumerator();
}
public void Clear()
{
_listImplementation.ForEach(x => x.PropertyChanged -= ItemOnPropertyChanged);
_listImplementation.Clear();
}
public bool Contains(T item)
{
return _listImplementation.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_listImplementation.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
item.PropertyChanged -= ItemOnPropertyChanged;
return _listImplementation.Remove(item);
}
public int Count => _listImplementation.Count;
public bool IsReadOnly => false;
public int IndexOf(T item)
{
return _listImplementation.IndexOf(item);
}
public void Insert(int index, T item)
{
item.PropertyChanged += ItemOnPropertyChanged;
_listImplementation.Insert(index, item);
}
public void RemoveAt(int index)
{
_listImplementation.RemoveAt(index);
}
public T this[int index]
{
get => _listImplementation[index];
set => _listImplementation[index] = value;
}
public event PropertyChangedEventHandler PropertyChanged;
}
Have we use PropertyChangeListener for this task? Like it is shown here.
public FocusManagerListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
if ("focusOwner".equals(propertyName) {
...
} else if ("focusedWindow".equals(propertyName) {
...
}
}
...
}
I just ported ItemPropertyChangedNotifyingList to ItemChangeList.
In code, I changed this part.
Used 'ArrayList' to hold elements instead of 'List` in C#
In copyTo, I used Java 8 Stream. Since you tag 'android', I used Lightweight-Stream-API to achieve same feature of copyTo.
Java doesn't support get, set syntax, i divide to two methods.
import com.annimon.stream.Stream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ItemChangedList<T> {
private List<T> _listImplementation = new ArrayList<>();
private List<OnPropertyChangedObserver<T>> _changedObserverList = new ArrayList<>();
public static final String ITEM_ADDED = "bbed36af-0b7b-4e53-abc9-02d6a14d7f34";
public static final String ITEM_REMOVED = "7390116e-586d-4e62-9343-5b82b0a8c6c5";
public void add(T item) {
sendPropertyChanged(item, ITEM_ADDED);
_listImplementation.add(item);
}
public Iterator<T> iterator() {
return _listImplementation.iterator();
}
public void clear() {
for (T item : _listImplementation) {
sendPropertyChanged(item, ITEM_REMOVED);
}
_listImplementation.clear();
}
public boolean contains(T item) {
return _listImplementation.contains(item);
}
public void copyTo(T[] array, int arrayIndex) {
// Using https://github.com/aNNiMON/Lightweight-Stream-API
_listImplementation.addAll(Stream.of(array).skip(arrayIndex).toList());
// Traditional Java way
// _listImplementation.addAll(Arrays.stream(array).skip(arrayIndex).collect(Collectors.toList()));
}
public boolean remove(T item) {
sendPropertyChanged(item, ITEM_REMOVED);
return _listImplementation.remove(item);
}
public int count() {
return _listImplementation.size();
}
public boolean isReadOnly() {
return false;
}
public int indexOf(T item) {
return _listImplementation.indexOf(item);
}
public void insert(int index, T item) {
sendPropertyChanged(item, ITEM_ADDED);
_listImplementation.add(index, item);
}
public void removeAt(int index) {
_listImplementation.remove(index);
}
public T get(int index) {
return _listImplementation.get(index);
}
public void set(int index, T item) {
_listImplementation.set(index, item);
}
public void addObserver(OnPropertyChangedObserver<T> observer) {
_changedObserverList.add(observer);
}
public void removeObserver(OnPropertyChangedObserver<T> observer) {
_changedObserverList.remove(observer);
}
public void clearObserver() {
_changedObserverList.clear();
}
private void sendPropertyChanged(T item, String args) {
for (OnPropertyChangedObserver<T> observer : _changedObserverList) {
observer.onChanged(item, args);
}
}
public interface OnPropertyChangedObserver<T> {
void onChanged(T item, String args);
}
}
Other way is extends ArrayList instead _listImplementation. it can be provide more functionally. Personally, I prefer this way. Gist
Edit-1) Oh, i forget add args in OnPropertyChangeObserver.
Edit-2) Let Kotlin optimize this! Gist

C# List implementation... in Java

I'm learning Java and I'm trying to do something I've always done in C#... in Java.
The goal is to wrap the class "MyItem" into a List of "MyItems". This makes it easier to reason about (MyItems is much easier to read/understand than List<MyItem>... or, say, I need to make it something more complicated like IEnumerable<KeyValuePair<string,List<Dictionary<int,bool>>>>... then ask for a MyKVPDictionaries instead of List<IEnumerable<KeyValuePair<...>>>>>).
Just looking around... It seems like C# allows you to keep the default implementations of stuff (Look below, .Add just works).
Looking at Java... is there a way to implement a list as done in c#? Or do I have to manually implement the individual parts of the List manually? (.add, .list, .contains, etc).
Below I have a "basic" implementation of a Class... and a List<Class> in C#.
Is it really that much more work to implement class MyItems implements List<MyItem> in Java or am I missing something to simplify the process?
(The Java code is only the MyItems.java class file with Resharper "Auto Implement missing members" stubs via IntelliJ).
C# version .NetFiddle:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var myItems = new MyItems();
myItems.Add(new MyItem("Hello"));
myItems.Add(new MyItem(" "));
myItems.Add(new MyItem("World"));
myItems.Add(new MyItem("!"));
foreach(var item in myItems)
Console.Write(item.Name);
}
}
public class MyItems : List<MyItem>
{
}
public class MyItem
{
public MyItem(string name)
{
Name = name;
}
public string Name { get; private set; }
}
Java Version start/stub:
package items;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class MyItems implements List<MyItem> {
#Override
public int size() {
return 0;
}
#Override
public boolean isEmpty() {
return false;
}
#Override
public boolean contains(Object o) {
return false;
}
#Override
public Iterator<MyItem> iterator() {
return null;
}
#Override
public Object[] toArray() {
return new Object[0];
}
#Override
public <T> T[] toArray(T[] a) {
return null;
}
#Override
public boolean add(MyItem generatePreSignedUrl) {
return false;
}
#Override
public boolean remove(Object o) {
return false;
}
#Override
public boolean containsAll(Collection<?> c) {
return false;
}
#Override
public boolean addAll(Collection<? extends MyItem> c) {
return false;
}
#Override
public boolean addAll(int index, Collection<? extends MyItem> c) {
return false;
}
#Override
public boolean removeAll(Collection<?> c) {
return false;
}
#Override
public boolean retainAll(Collection<?> c) {
return false;
}
#Override
public void clear() {
}
#Override
public MyItem get(int index) {
return null;
}
#Override
public MyItem set(int index, MyItem element) {
return null;
}
#Override
public void add(int index, MyItem element) {
}
#Override
public MyItem remove(int index) {
return null;
}
#Override
public int indexOf(Object o) {
return 0;
}
#Override
public int lastIndexOf(Object o) {
return 0;
}
#Override
public ListIterator<MyItem> listIterator() {
return null;
}
#Override
public ListIterator<MyItem> listIterator(int index) {
return null;
}
#Override
public List<MyItem> subList(int fromIndex, int toIndex) {
return null;
}
}
Java's List type is an interface, the counterpart of C#'s IList. You'll have to write most of the methods from scratch if you want to implement it. The counterpart of C#'s concrete List class would be Java's ArrayList:
public class MyItems extends ArrayList<MyItem> {

Use Vaadin TreeTable like a normal Tree

Since Vaadin Tree does not support lazy loading I would like to use the TreeTable.
The TreeTable should look like a normal Tree, without headers and zebra row style.
This is what I got so far:
TreeTable mainTree = new TreeTable();
mainTree.setSizeFull();
mainTree.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
mainTree.setColumnCollapsingAllowed(false);
What else should I set and how do I get rid of the zebra pattern?
Consider implenting a lazy load mechanism yourself, wherein you load the root of three. Then you add an ExpandListener which, upon called, loads the children objects and adds them to the node.
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
final Tree t = new Tree();
t.addItem(new TreeNode(0));
t.addExpandListener(new ExpandListener() {
#Override
public void nodeExpand(ExpandEvent event) {
TreeNode node = (TreeNode) event.getItemId();
for (TreeNode child : node.getMyChildren()){
t.addItem(child);
t.setParent(child, node);
}
}
});
layout.addComponent(t);
}
}
Even though in Vaadin documentation it says lazy loading for Tree is not supported, I managed to implement the following lazy loading Hierarchical interface.
It's very important to store all elements in a local structure (in my case in the HashMap hierarchy), do not read elements multiple times this does not work. I think because Vaadin does not use equals() and hashCode().
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.softmodeler.common.CommonPlugin;
import com.softmodeler.model.OutputNode;
import com.softmodeler.service.IViewService;
import com.vaadin.data.Container.Hierarchical;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItem;
/**
* #author Flavio Donzé
* #version 1.0
*/
public class OutputNodeHierachical implements Hierarchical {
private static final long serialVersionUID = 8289589835030184018L;
/** the view service */
private IViewService service = CommonPlugin.getService(IViewService.class);
/** collection of all root nodes */
private List<OutputNode> rootNodes = null;
/** parent=>children mapping */
private Map<OutputNode, List<OutputNode>> hierarchy = new HashMap<>();
/**
* constructor
*
* #param rootNodes collection of all root nodes
*/
public OutputNodeHierachical(List<OutputNode> rootNodes) {
this.rootNodes = Collections.unmodifiableList(rootNodes);
addToHierarchy(rootNodes);
}
#Override
public Collection<?> getChildren(Object itemId) {
try {
List<OutputNode> children = hierarchy.get(itemId);
if (children == null) {
OutputNode node = (OutputNode) itemId;
children = service.getChildren(node.getNodeId(), false);
hierarchy.put(node, children);
// add children to hierarchy, their children will be added on click
addToHierarchy(children);
}
return children;
} catch (Exception e) {
VaadinUtil.handleException(e);
}
return null;
}
/**
* add each element to the hierarchy without their children hierarchy(child=>null)
*
* #param children elements to add
*/
private void addToHierarchy(List<OutputNode> children) {
for (OutputNode child : children) {
hierarchy.put(child, null);
}
}
#Override
public boolean areChildrenAllowed(Object itemId) {
return !((OutputNode) itemId).getChilds().isEmpty();
}
#Override
public boolean hasChildren(Object itemId) {
return !((OutputNode) itemId).getChilds().isEmpty();
}
#Override
public Object getParent(Object itemId) {
String parentId = ((OutputNode) itemId).getParentId();
for (OutputNode node : hierarchy.keySet()) {
if (node.getNodeId().equals(parentId)) {
return node;
}
}
return null;
}
#Override
public Collection<?> rootItemIds() {
return rootNodes;
}
#Override
public boolean isRoot(Object itemId) {
return rootNodes.contains(itemId);
}
#Override
public Item getItem(Object itemId) {
return new BeanItem<OutputNode>((OutputNode) itemId);
}
#Override
public boolean containsId(Object itemId) {
return hierarchy.containsKey(itemId);
}
#Override
public Collection<?> getItemIds() {
return hierarchy.keySet();
}
#Override
public int size() {
return hierarchy.size();
}
#Override
public boolean setParent(Object itemId, Object newParentId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public boolean removeAllItems() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public Class<?> getType(Object propertyId) {
throw new UnsupportedOperationException();
}
#Override
public Collection<?> getContainerPropertyIds() {
throw new UnsupportedOperationException();
}
#Override
public Property<?> getContainerProperty(Object itemId, Object propertyId) {
throw new UnsupportedOperationException();
}
#Override
public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
#Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}
Adding the container to the Tree like this:
OutputNodeHierachical dataSource = new OutputNodeHierachical(rootNodes);
Tree mainTree = new Tree();
mainTree.setSizeFull();
mainTree.setContainerDataSource(dataSource);
mainTree.addItemClickListener(new ItemClickListener() {
private static final long serialVersionUID = -413371711541672605L;
#Override
public void itemClick(ItemClickEvent event) {
OutputNode node = (OutputNode) event.getItemId();
openObject(node.getObjectId());
}
});

Categories