Add extra column to beancontainer or beanitemcontainer

Hello,
I am wondering how I can add additional columns to a bean item container or a bean container. I am currently using a beancontainer and have a Bean that is passed across a webservice and added to the container.
However, I would like to add additional columns to the container that are not part of the bean. I have tried a couple of ways to try and add but it always tells me to “addNestedProperty” which doesnt make sense to me. Any help is appreciated.

The big question is what kinds of Properties you are adding. Do you have your custom implementation of the Property class? Note that addNestedProperty() can also be used to add simple method properties.

Anyway, to add something else than simple or nested method call based properties, you need to subclass the Bean(Item)Container class to be able to call the protected method addContainerProperty(String propertyId, VaadinPropertyDescriptor propertyDescriptor). Then define your own VaadinPropertyDescriptor implementation for the properties you want to add. The property descriptor class is usually quite trivial, with only three short methods to implement - you can check the existing MethodPropertyDescriptor etc. for (somewhat more complex) examples.

You might also be interested in my little prototype of a container
MCont
, which supports combining the properties of multiple subclasses in a single container, with empty values returned for missing properties. I haven’t published it in the Directory yet because it hasn’t really been tested properly and is missing a few features, but it can at least act as an example.

Hi Henri,

I tried what you suggested but it didn’t work. I want to add a dynamic property on an immutable object based on a resource key. The resource key resolves to a description for the user’s current locale.

In this simple case I can just use an IndexContainer (it’s being used in a ComboBox) but it would be nice to know how to do this correctly regardless.


final BeanItemContainer<SubscriptionPackageRef> container = new BeanItemContainer<>(SubscriptionPackageRef.class);
container.addNestedContainerProperty("description");

final BeanItem<SubscriptionPackageRef> item = container.addBean(SubscriptionPackageRef.getInstance("1", "RESOURCEKEY"));
item.getItemProperty("description").setValue("TEST");

Which results in:


java.lang.IllegalArgumentException: Bean property 'description' not found
	at com.vaadin.data.util.NestedMethodProperty.initialize(NestedMethodProperty.java:143)
	at com.vaadin.data.util.NestedMethodProperty.<init>(NestedMethodProperty.java:103)
	at com.vaadin.data.util.NestedPropertyDescriptor.<init>(NestedPropertyDescriptor.java:52)
	at com.vaadin.data.util.AbstractBeanContainer.addNestedContainerProperty(AbstractBeanContainer.java:794)

I tried this too but it’s unsupported operation.


container.addContainerProperty("description", String.class, null);

Thanks

For some clarifications:

Do you mean “dynamic” in the sense that the value is computed at run-time? Or that even the existence of the whole property from the point of view of the user of the Container varies from container instance to the other? In the latter case, would it depend on the properties of the items in the container?

How about “immutable” - do you mean that the instances are read-only, or that you cannot change the source code for that class.

If just the value needs to be computed on-the-fly and you want it to be accessible through the container, and you cannot add accessors to the bean classes, use the technique I mentioned above using a custom VaadinPropertyDescriptor .

On the other hand, if you just want to customize the caption of each item in a Table or ComboBox, you can use generated columns in a Table and customize captions in the ComboBox (with explicit caption mode if nothing else works), handling this on the presentation layer.

The use case here is the service layer returns a collection of immutable objects describing the available subscriptions for purchase. Each subscription has an ID, a resource key for resource bundle (locale aware description intended to be used in ComboBox caption) and a number of rules (not important for this discussion).

First off could you verify that adding a nested property DOES NOT work and that I’m not doing anything wrong in my example above.

Like you said I could use setItemCaption() but then I lose the ability to sort that the container provides and I’d have to do some extra work.

What I did was wrap the original object and use a BeanItemContainer which is an ok solution but creates extra object, i.e.


    public LocalizedSubscriptionPackage(final SubscriptionPackageRef delegate, final String localizedDescription) {
        this.delegate = checkNotNull(delegate);
        this.localizedDescription = checkNotNull(localizedDescription);
    }

    public void setSubscriptionPackages(final List<SubscriptionPackageRef> subscriptionPackages) {

        final BeanItemContainer<LocalizedSubscriptionPackage> container = new BeanItemContainer<>(LocalizedSubscriptionPackage.class);
        for (SubscriptionPackageRef ref : subscriptionPackages) {
            container.addBean(new LocalizedSubscriptionPackage(ref,
                    subscriptionPackageCodeRepository.resolveName(ref.getResourceKey(), getLocale())));
        }
        container.sort(new Object[] {"localizedDescription"}, new boolean[]
 {true});
        subscriptionSelector.setContainerDataSource(container);
    }

Was wondering if there was an easier way that didn’t require writing any extra code? The above isn’t horrible but looking for the most efficient way to achieve what I want for future.

Thanks!

If the subscriptions conform to the Java Beans specification, their simple properties should have been added automatically - those that have both a getter and a setter as read-write properties and those that only have a getter as read-only properties. The method addNestedProperty() is meant for adding properties of type “address.city” where there is an intermediate Address bean containing a city field.

The approach I mentioned above with a custom VaadinPropertyDescriptor is what I would use in your situation - there is not that much to write, and most of it could be written as a generic resource lookup property and property descriptor and a minimal Bean(Item)Container subclass if you might want to reuse those bits. This might even require less code than writing a wrapper for the beans.

Thanks I’ll take a closer look at VaadinPropertyDescriptor.