Grid: beanItemContainer property is array: how to get the data from the arr

I want to get data from an array into a vaadin grid.
Here are some relevant parts of my code:

From the Grid’s builder-class

[i]

Grid grid = new Grid();
for(int i = 0; i<numberColumns; i++){
String propertyId = “deliveryList[” + i + "]
";
grid.addColumn(propertyId);
}
[/i]

In the base class:

[i]

public class DeliveryVO {
private Integer deliveryList;

  public Integer getDeliveryList() {
                           return deliveryList;
              }
...

[/i]

and in the view where the grid should be displayed:

[i]

DeliveryVO deliveryVO1 = new deliveryVO(12);
final BeanItemContainer beanItemContainer = new BeanItemContainer(DeliveryVO.class);
beanItemContainer.addBean(deliveryVO1);

final Grid grid = new xGrid.Builder()
            .setNumberColumns(12)
            .setTimeGroup(TIME_GROUP.HOURLY).build();
grid.setContainerDataSource(beanItemContainer);
...
addComponent(grid);

[/i]

When i try to run this i get the following error:

java.lang.IllegalStateException: Found at least one column in Grid that does not exist in the given container: deliveryList[0]
with the header "Delivery List[0]
"

I can get data in the grid when i use the propertyId of an attribute in de DeliveryVO-class, but i cannot acces the data from the array… Can someone help we with getting this array-data into the Grid?

Hi Lieven,

Based on your examples it’s a bit hard to understand what exactly you’re trying to see as a result.

However, as a quick crash course in Vaadin containers.

  1. Think of the property id’s as columns in your table, i.e. every row will have all the properties (colums) that are in the container. They can be null, but they’ll be there for every row.
  2. Think of the itemId as rows, typically these would be your POJOs (DevliveryVO).
  3. The container dictates which properties are available, sortable, editable etc. (not the Grid,Table,Tree etc…)
  4. The Table or Tree can decide to show only a subset of the available columns (Table.setVisibleColumns()) or hide a colum in the case of the Grid API (Grid.removeColumn())).

So essentially your first task is to build the container and then use the Grid to display/render the container in the UI. I.e. the builder needs to set the container to the Grid before you start defining columns.

The BeanItemContainer is a special container in that it will read the field declarations (or getters and setters to be more exact) of the POJO that it uses and use those as propertyId’s. For your DeliveryVO example this means that the container will have one propertyId (deliveryList) which is of type Integer. You cannot add properties to a BeanItemContainer through the container API as there is no corresponding field in the DeliveryVO object to map to. The only way to add properties to a BeanItemContainer is to add fields (or actually getter methods) to the bean itself (DeliveryVO).

If your DeliveryVO object contains an array that you want to distribute over properties, you’ll have to build the container yourself as there no way for the BeanItemContainer to do the mapping automatically.

So let’s say that you have a DeliveryVO with a list of Integers that you want to map to properties, you could for instance do the following:

[code]
public class DeliveryVO {

    public List<Integer> deliveries = new ArrayList<Integer>();

    public List<Integer> getDeliveries() {
        return deliveries;
    }
}

//Just a method somewhere to create a list of deliverables and populate each deliverables list of integers.. 
private List<DeliveryVO> getDeliveries() {
    ArrayList<DeliveryVO> deliveriesList = new ArrayList<DeliveryVO>();

    DeliveryVO deliveryVO = new DeliveryVO();
    for (int i = 0; i < 12; i++) {
        deliveryVO.getDeliveries().add(i + 1000);
        deliveriesList.add(deliveryVO);
    }

    return deliveriesList;
}

[/code]— In the UI code —

[code]
// Build the container manually
IndexedContainer indexedContainer = new IndexedContainer();
for (int i = 0; i < 12; i++) {
// Add the properties (columns) we want to show in the grid to the
// container
indexedContainer.addContainerProperty(“deliveryList[” + i + "]
",
Integer.class, null);
}

    // Get all the rows and populate the container
    List<DeliveryVO> allRows = getDeliveries();
    for (DeliveryVO delivery : allRows) {

        // First we add the item
        indexedContainer.addItem(delivery);

        for (int i = 0; i < 12; i++) {
            // Then we set the values for the properties
            indexedContainer.getContainerProperty(delivery,
                    "deliveryList[" + i + "]

").setValue(
delivery.getDeliveries().get(i));
}
}

    Grid grid = new Grid();
    grid.setContainerDataSource(indexedContainer);
    layout.addComponent(grid);

[/code]Another solution is to add getters for each property to the DeliveryVO, or wrap it inside a proxy object that delegates the getters to the specific index of the list and then use the Proxy in the BeanItemContainer instead of the entity.

[code]
public class DeliveryVOProxy{

private DeliveryVO deliveryVO;

public DeliveryVOProxy(DeliveryVO deliveryVO) {
    this.deliveryVO = deliveryVO;
}
public Integer getDeliveryList0(){
    return deliveryVO.getDeliveries().get(0); 
}
public Integer getDeliveryList1(){
    return deliveryVO.getDeliveries().get(1); 
}
public Integer getDeliveryList2(){
    return deliveryVO.getDeliveries().get(2); 
}
 
//Rest of the getters... 

}
[/code]If you want to be fancy you can also get the same result with a BeanItemContainer if you wrap it inside a GeneratedPropertyContainer. However, as a starting point with Vaadin containers, I’d start with the IndexedContainer so that you’ll get familiar with the Container API. Also this approach can sometimes be slower in the terms of performance as generated properties are generated every time they are requested, whereas the values in the indexed container are created only once when the container is created.

GeneratedPropertyContainer solution just for reference:

[code]
BeanItemContainer bic = new BeanItemContainer(DeliveryVO.class);
bic.addAll(allRows);

    GeneratedPropertyContainer generatedPropertyContainer = new GeneratedPropertyContainer(bic);

    for (int i = 0; i < 12; i++) {
        final int indexForThisProperty = i;
        generatedPropertyContainer.addGeneratedProperty("deliveryList[" + i
                + "]", new PropertyValueGenerator<Integer>() {

            @Override
            public Integer getValue(Item item, Object itemId,
                    Object propertyId) {
                if (itemId instanceof DeliveryVO) {
                    return ((DeliveryVO) itemId).getDeliveries().get(indexForThisProperty);
                }

                return null;
            }

            @Override
            public Class<Integer> getType() {
                return Integer.class;
            }
        });
    }

    Grid grid = new Grid();
    grid.setContainerDataSource(generatedPropertyContainer);
    grid.removeColumn("deliveries");

    layout.addComponent(grid);

[/code]Hope this helps to clarify it a bit.

Best,

Hi Petri,

I tried your first option and succeeded in solving my problem.
Thank you very much for your response.

Cheers,
Lieven