Get properties of BeanItem in HierarchicalContainer

I have a POJO, which I wrap in a BeanItem before adding to a HierarchicalContainer.

Yet, the HierarhicalContainer cannot acces the properties of the BeanItem - how do I do this?

class Category {
 protected Category[] children;
 //POJO with getters and setters
 }
HierarchicalContainer container = new HierarchicalContainer();
Category root = Category.tree(website.api, null);

new Object(){
	public void addChildren(HierarchicalContainer container,BeanItem<Category> item)
	{	container.addItem(item); 
		container.setChildrenAllowed(item, item.getBean().hasChildren());
					
		for(int i = 0; i<item.getBean().children.length;i++)
		{	BeanItem<Category> child = new BeanItem<Category>(item.getBean().children[i]
);
			addChildren(container,child); //adds child to container, recursive
			container.setParent(child, item); //connects parent with child
		}					
				
	}
}.addChildren(container,new BeanItem<Category>(root));

Here is a solution:
The POJO must implement the TreeItem interface.

  • items are identified with an integer
  • items have a parent-id
  • items have an int array of children-ids

public interface TreeItem<T> {
	public T[] getChildren();
	public int[] getChildrenIds();
	public int getParentId();
	public int getId();	
}

Then, I extended BeanContainer to implement HierarchicalContainer.


WARNING:
Only use addBean(BEANTYPE bean)!
This method adds the entire tree recursively!
Adding items with a custom ID that does not match the Bean’s ID may lead to unexpected results, and I did not shield those methods!


import java.util.ArrayList;
import com.vaadin.data.Container;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.data.util.BeanItem;

public class HierarchicalBeanContainer<BT extends TreeItem<BT>> extends BeanContainer<Integer,BT> 
implements Container.Hierarchical {
	private static final long serialVersionUID = -7483903937657002180L;
	private ArrayList<Integer> rootitems = new ArrayList<Integer>();
	
	public HierarchicalBeanContainer(Class<BT> type)
	{	super(type);		
		rootitems.add(0);
	}
	
	public HierarchicalBeanContainer(Class<BT> type, int rootid)
	{	super(type);		
		super.setBeanIdResolver(new BeanIdResolver<Integer,BT>() {
			private static final long serialVersionUID = 14343948239048L;
			@Override 
			public Integer getIdForBean(BT bean) {
				return bean.getId();
			}			
		});
		rootitems.add(rootid);
	}
	
	public BeanItem<BT> addBean(BT bean)
	{	BeanItem<BT> item = super.addBean(bean);
		BT[] children = bean.getChildren();
		for(int i = 0; i<children.length; i++)
			addBean(children[i]
);
		return item;
	}

	@Override
	public ArrayList<Integer> getChildren(Object itemId) {
		int[] ids = getItem(itemId).getBean().getChildrenIds();		
		ArrayList<Integer> list = new ArrayList<Integer>(ids.length);
		for(int i = 0;i<ids.length;i++)
			list.add(ids[i]
);
		return list;
	}

	@Override
	public Integer getParent(Object itemId) {
		return getItem(itemId).getBean().getParentId();
	}

	@Override
	public ArrayList<Integer> rootItemIds() {
		return rootitems;
	}
	
	public void addRoot(int id)
	{	if(!rootitems.contains(id))
			rootitems.add(id);		
	}
	
	public void removeRoot(int id)
	{	if(rootitems.contains(id))
			rootitems.remove(id);
	}

	@Override
	public boolean setParent(Object itemId, Object newParentId)
			throws UnsupportedOperationException {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean areChildrenAllowed(Object itemId) {
		return hasChildren(itemId);
	}

	@Override
	public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed)
			throws UnsupportedOperationException {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean isRoot(Object itemId) {
		return rootitems.contains(getItem(itemId).getBean().getId());
	}


	@Override
	public boolean hasChildren(Object itemId) {
		int[] children = getItem(itemId).getBean().getChildrenIds();
		return (children != null) && (children.length > 0);
	}
}

You can also wrap the BeanContainer in ContainerHierarchicalWrapper to achieve this.

EDIT: it is actually better to use HierarchicalContainer, since it can deal with sorting and filtering (it’s not an easy feat since filtering can remove parent items; HierarchicalContainer makes sure that those parent items are still present in the tree even though they do not match the filter).

It is easy to extend HierarchicalContainer and add properties from a bean class, for example
https://gist.github.com/mvysny/4307b4b76c13bc159c4dae77cff9549f