Vaadin TreeTable field factory is executed multiple times

In an editable TreeTable the field factory for a single propertyId and ItemId the field factory is executed so many times.

I have one TreeTable with
5
records. All records are having
4
child.The table has
4
column. First time for 5 record the field factory create field is called
5*4=20
times. It is needed for for no of column and no of rows. I expanded one record and its having
4
child row. In this case the field factory is called
544=80
times for each row. Here total no of parent rows are
5
and child rows are
4
. So total rows=9. When I click expand of one row total 9 rows to paint in table. So its calling the field facory about
9*4 factorial
times. Its slowig down the performance of table. Please advice any suggession.

I made a quick test with a field factory in TreeTable and didn’t notice quite the problem you had, if I understood your problem correctly. When your TreeTable with gets fully expanded, you should expect 5*(1+4)*4=100 field factory calls in all, but not “for each row”. Perhaps there is something different in your case.

Every time there is any change in the TreeTable, such as expanding an item, the field factory is called exactly once for every visible cell (rows*columns). Hence, it does call the field factory also for all fields that were previously visible, which does not seem necessary. That’s something that would deserve a ticket. Although, it’s quite possible that Grid gets hierarchical support before that would be fixed.

Calling the field factory is itself not so expensive for rendering, as that happens on the server-side. It’s the rendering of the generated components that takes time.

The only related ticket that I can find is
#2071
for Table. It’s a bit old and is only for the server-side factories; even if cached on the server-side, the components would get refreshed on the client-side and make the rendering slow. And it doesn’t address the special case with TreeTable, where only the new visible items should be generated.

Hi Marko,
Can you please check the attached sample project(SampleProject.zip). I have given System.out.print when createField is executed for the field factory.

19151.zip (388 KB)

Ooook, right, now I can see the problem.

I added the following debug code:

        final HashMap<String,Integer> creations = new HashMap<String,Integer>();
        tbl.setTableFieldFactory(new DefaultFieldFactory() {
            int calls = 0;

            @Override
            public Field createField(final Container container, final Object itemId,
                    final Object propertyId, Component uiContext) {
                System.out.println("call " + calls++ + " tbl itemId=" + itemId + "  propertyId=" + propertyId);
                String key = itemId.toString() + "," + propertyId.toString();
                if (creations.containsKey(key))
                    creations.put(key, creations.get(key) + 1);
                else
                    creations.put(key, 1);
                
                if (propertyId.toString().startsWith("n")) {
                    final TextField tf = new TextField();
                    tf.setImmediate(true);

                    return tf;
                }
                return null;
            }
        });
        
        addComponent(new Button("Report", new ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                System.out.println("Table has " + hierarchicalContainer.size() + " items");
                for (Object itemId: hierarchicalContainer.getItemIds()) {
                    System.out.print("item " + hierarchicalContainer.getContainerProperty(itemId, "id").getValue() + " ");

                    for (Object propertyId: hierarchicalContainer.getContainerPropertyIds()) {
                        String key = itemId.toString() + "," + propertyId.toString();
                        int count = creations.get(key);
                        System.out.print(propertyId.toString() + ":" + count + " ");
                        
                        // Reset the count
                        creations.put(key, 0);
                    }
                    System.out.println("");
                }
            }
        }));

When only the 10 top-level items are shown, it calls the factory 40 times, which is proper. However, expanding an item, so that 20 items are visible, causes some 2460 calls…

Analyzing it further, it shows that for some items, the factory has been called even some 42 times…

Table has 20 items item 0 id:42 name:42 no:42 hierarchyNo:42 item 1 id:42 name:42 no:42 hierarchyNo:42 item 2 id:42 name:42 no:42 hierarchyNo:42 item 3 id:42 name:42 no:42 hierarchyNo:42 item 4 id:42 name:42 no:42 hierarchyNo:42 item 5 id:42 name:42 no:42 hierarchyNo:42 item 6 id:42 name:42 no:42 hierarchyNo:42 item 7 id:42 name:42 no:42 hierarchyNo:42 item 8 id:42 name:42 no:42 hierarchyNo:42 item 9 id:42 name:42 no:42 hierarchyNo:42 item 0 id:41 name:41 no:41 hierarchyNo:41 item 1 id:37 name:37 no:37 hierarchyNo:37 item 2 id:33 name:33 no:33 hierarchyNo:33 item 3 id:29 name:29 no:29 hierarchyNo:29 item 4 id:25 name:25 no:25 hierarchyNo:25 item 5 id:21 name:21 no:21 hierarchyNo:21 item 6 id:17 name:17 no:17 hierarchyNo:17 item 7 id:13 name:13 no:13 hierarchyNo:13 item 8 id:9 name:9 no:9 hierarchyNo:9 item 9 id:5 name:5 no:5 hierarchyNo:5 So for each next item, the fields for the above items are generated 4 times, that is, exactly the number of properties in each item… So the reason seems to be that
all the existing fields in the TreeTable are regenerated every time

you set the value of one table cell
… You are doing that in the ExpandListener, and call setValue() in the addItem() method for four times.

So, please
file a ticket
and link to this thread.

For a workaround, I’d think it’s easiest to do setContainerDataSource(null) for the TreeTable while you’re adding the items in the container and after you’ve added them all, set the original container back again. Silly, but yeah it’s a workaround. For perhaps a better workaround, you could extend TreeTable and use the protected disableContentRefreshing() and enableContentRefreshing() while adding new items.


https://dev.vaadin.com/ticket/17838

Wow, I was messing around with TreeTable and just found that this nasty bug is still open.

Freaking amazing.