How to use Table.ColumnGenerator implementations in a Table in Vaadin?

Hi everyone, I have some troubles with the column generators, actually I think they are explained in a little understandable way for a Vaadin newbie. Here is the code I wrote:

// Generated Table columns

        Table tableWithGeneratedCol = new Table();

        tableWithGeneratedCol.addContainerProperty(

                "date",     Date.class,   null, "Date",         null, null);

        tableWithGeneratedCol.addContainerProperty(

                "quantity", Double.class, null, "Quantity (l)", null, null);

        tableWithGeneratedCol.addContainerProperty(

                "price",    Double.class, null, "Price (e/l)",  null, null);

        tableWithGeneratedCol.addContainerProperty(

                "total",    Double.class, null, "Total (e)",    null, null);


        // Some rows as example

        tableWithGeneratedCol.addGeneratedColumn("date", new DateColumnGenerator());

        tableWithGeneratedCol.addGeneratedColumn("quantity", new ValueColumnGenerator("%.2f l"));

        tableWithGeneratedCol.addGeneratedColumn("price", new PriceColumnGeneretor());

        tableWithGeneratedCol.addGeneratedColumn("total",new TotalColumnGenerator("%.2f e", "quantity", "price"));

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(), // date column
                                                     new Double(10),                     // quantity column
                                                     new Double(10),                    // price column
                                                    // nothing here                        // total column
                                                    }, 1); // itemId
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),
                                                     new Double(16.2),                     // quantity column
                                                     new Double(21.2),                    // price column
                                                    // nothing here                        // total column
                                                    }, 2); // itemId
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),
                                                     new Double(10),                     // quantity column
                                                     new Double(22),                    // price column
                                                     // nothing here                    // total column                                            
                                                    }, 3); // itemId
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),
                                                     new Double(10),                     // quantity column
                                                     new Double(20),                    // price column
                                                     // nothing here                    // total column
                                                    }, 4); // itemId
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),
                                                     new Double(15),                     // quantity column
                                                     new Double(19.12),                    // price column
                                                     // nothing here                    // total column
                                                    }, 5); // itemId
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),
                                                     new Double(10),                     // quantity column
                                                     new Double(20.30),                    // price column
                                                    // nothing here                    // total column        
                                                    }, 6); // itemId
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),
                                                     new Double(50),                     // quantity column
                                                     new Double(32.89),                    // price column
                                                     // nothing here                    // total column
                                                    }, 7); // itemId
        tableWithGeneratedCol.setVisibleColumns(new Object[] {"date", "quantity", "price", "total"});
        tableWithGeneratedCol.setPageLength(tableWithGeneratedCol.size());
        layout.addComponent(tableWithGeneratedCol);

This code is placed inside the UI’s init() method. Now the column generators:

DateColumnGenerator:

public class DateColumnGenerator implements ColumnGenerator {




/**

     * 

     */

private static final long serialVersionUID = 1L;




@Override

public Component generateCell(Table source, Object itemId, Object columnId) {

        System.out.println("TIMEZONE : " + TimeZone.getDefault().getID());

        //Date date = new Date();

        Property<?> prop = source.getItem(itemId).getItemProperty(columnId);

        if (prop.getType().equals(Date.class)) {

            Date date = (Date) prop.getValue();

            SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy, HH:mm:ss");

            sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));

            return new Label(sdf.format(date));

        }

        return null;

    }




}

ValueColumnGenerator:

/** Formats the value in a column containing Double objects. */

class ValueColumnGenerator implements Table.ColumnGenerator {

    /**

     * 

     */

private static final long serialVersionUID = 1L;

String format; /* Format string for the Double values. */




    /**

     * Creates double value column formatter with the given

     * format string.

     */

    public ValueColumnGenerator(String format) {

        this.format = format;

    }




    /**

     * Generates the cell containing the Double value.

     * The column is irrelevant in this use case.

     */

    public Component generateCell(Table source, Object itemId,

                                  Object columnId) {

        // Get the object stored in the cell as a property

        Property<?> prop = source.getItem(itemId).getItemProperty(columnId);

        if (prop.getType().equals(Double.class)) {

            Label label = new Label(String.format(format, new Object[] { (Double) prop.getValue() }));

            

            // Set styles for the column: one indicating that it's

            // a value and a more specific one with the column

            // name in it. This assumes that the column name

            // is proper for CSS.

            label.addStyleName("column-type-value");

            label.addStyleName("column-" + (String) columnId);

            return label;

        }

        return null;

    }

}

PriceColumnGenerator:

public class PriceColumnGeneretor implements ColumnGenerator {




/**

     * 

     */

private static final long serialVersionUID = 1L;

    

@Override

public Component generateCell(Table source, Object itemId, Object columnId) {

        Property<?> prop = source.getItem(itemId).getItemProperty(columnId);

        if (prop.getClass().equals(Double.class)) {

            Double price = (Double) prop.getValue();

            String priceStr = String.format("%.2 €", price);

            return new Label(priceStr);

        }

        return null;

    }




}

TotalColumnGenerator:

public class TotalColumnGenerator implements Table.ColumnGenerator {




/**

     * 

     */

private static final long serialVersionUID = 1L;

    

protected String format;

protected String quantityId;

protected String priceId;

    

public TotalColumnGenerator(String format, String quantityId, String priceId) {

        this.format = format;

        this.quantityId = quantityId;

        this.priceId = priceId;

    }

    

@Override

public Component generateCell(Table source, Object itemId, Object columnId) {

        Double quantity = (Double) source.getItem(itemId).getItemProperty(this.quantityId).getValue();

        Integer price = (Integer) source.getItem(itemId).getItemProperty(this.priceId).getValue();

        String res = String.format(this.format, new Double(quantity * price));

                

        return new Label(res);

    }




}

But my problem is that the resulting table is empty, i.e. it has no rows… Why does this happen? What should I do in order to implement properly the column generators inside a Table component? I am asking this all because in Book of Vaadin which I am reading nothing is said about this, only snippets of code are given, but not how column generators should work as a whole…

So how can I actually make this code work properly?

Thank you for the attention!

hi, first of all, provide some default value for column “total”, second if you learn with attention about ColumnGenerator you supposed to know when must call method for generating, i.e. after table is populated and not before, when the table is empty, and what is that : if (prop.getType().equals(Date.class)) ?, you must change that horrible code with ‘instanceof’ check.

@Pavlon, thank you for your response!

I have tried to put
tableWithGeneratedCol.addGeneratedColumn()
method calls
after

tableWithGeneratedCol.addItem()
method calls, and the code:

// Generated Table columns

        Table tableWithGeneratedCol = new Table();

        

        tableWithGeneratedCol.addContainerProperty(

                "date",     Date.class,   null, "Date",         null, null);

        tableWithGeneratedCol.addContainerProperty(

                "quantity", Double.class, null, "Quantity (l)", null, null);

        tableWithGeneratedCol.addContainerProperty(

                "price",    Double.class, null, "Price (e/l)",  null, null);

        tableWithGeneratedCol.addContainerProperty(

                "total",    Double.class, null, "Total (e)",    null, null);

        
        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(), // date column

                                                     new Double(10),                     // quantity column

                                                     new Double(10),                    // price column

                                                     new Double(0)                    // total column default value
                                                    }, 1); // itemId

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),

                                                     new Double(16.2),                     // quantity column

                                                     new Double(21.2),                    // price column

                                                     new Double(0)                        // total column

                                                    }, 2); // itemId

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),

                                                     new Double(10),                     // quantity column

                                                     new Double(22),                    // price column

                                                     new Double(0)                    // total column                                            

                                                    }, 3); // itemId

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),

                                                     new Double(10),                     // quantity column

                                                     new Double(20),                    // price column

                                                     new Double(0)                    // total column

                                                    }, 4); // itemId

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),

                                                     new Double(15),                     // quantity column

                                                     new Double(19.12),                    // price column

                                                     new Double(0)                                            

                                                    }, 5); // itemId

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),

                                                     new Double(10),                     // quantity column

                                                     new Double(20.30),                    // price column

                                                     new Double(0)                    // total column        

                                                    }, 6); // itemId

        tableWithGeneratedCol.addItem(new Object[] { new GregorianCalendar().getTime(),

                                                     new Double(50),                     // quantity column

                                                     new Double(32.89),                    // price column

                                                     new Double(0)                    // total column

                                                    }, 7); // itemId

        

        tableWithGeneratedCol.addGeneratedColumn("date", new DateColumnGenerator());

        tableWithGeneratedCol.addGeneratedColumn("quantity", new ValueColumnGenerator("%.2f l"));

        tableWithGeneratedCol.addGeneratedColumn("price", new PriceColumnGeneretor());

        tableWithGeneratedCol.addGeneratedColumn("total",new TotalColumnGenerator("%.2f e", "quantity", "price"));

        

        tableWithGeneratedCol.setVisibleColumns(new Object[] {"date", "quantity", "price", "total"});

        tableWithGeneratedCol.setPageLength(tableWithGeneratedCol.size());

        layout.addComponent(tableWithGeneratedCol);

Now results in a

com.vaadin.ui.Table$CacheUpdateException: Error during Table cache update. Additional causes not shown.

Here is the stacktrace:

SEVERE: 

com.vaadin.ui.Table$CacheUpdateException: Error during Table cache update. Additional causes not shown.

    at com.vaadin.ui.Table.maybeThrowCacheUpdateExceptions(Table.java:1739)

    at com.vaadin.ui.Table.refreshRenderedCells(Table.java:1728)

    at com.vaadin.ui.Table.attach(Table.java:4244)

    at com.vaadin.ui.AbstractComponent.setParent(AbstractComponent.java:484)

    at com.vaadin.ui.AbstractComponentContainer.addComponent(AbstractComponentContainer.java:210)

    at com.vaadin.ui.AbstractOrderedLayout.addComponent(AbstractOrderedLayout.java:90)

    at com.example.table_chapter_5_21.TableUI.init(TableUI.java:352)

    at com.vaadin.ui.UI.doInit(UI.java:645)

    at com.vaadin.server.communication.UIInitHandler.getBrowserDetailsUI(UIInitHandler.java:222)

    at com.vaadin.server.communication.UIInitHandler.synchronizedHandleRequest(UIInitHandler.java:74)

    at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)

    at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1406)

    at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:305)

    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)

    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)

    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)

    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)

    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)

    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)

    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)

    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)

    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)

    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)

    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)

    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)

    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

    at java.lang.Thread.run(Thread.java:745)

Caused by: java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer

    at com.example.table_chapter_5_21.TotalColumnGenerator.generateCell(TotalColumnGenerator.java:27)

    at com.example.table_chapter_5_21.TotalColumnGenerator.generateCell(TotalColumnGenerator.java:1)

    at com.vaadin.ui.Table.parseItemIdToCells(Table.java:2334)

    at com.vaadin.ui.Table.getVisibleCellsNoCache(Table.java:2195)

    at com.vaadin.ui.Table.refreshRenderedCells(Table.java:1717)

    ... 34 more




Dec 15, 2014 8:15:58 PM org.apache.catalina.core.StandardWrapperValve invoke

SEVERE: Servlet.service() for servlet [com.example.table_chapter_5_21.TableUI$Servlet]
 in context with path 
[/Table_Chapter_5.21] threw exception [com.vaadin.server.ServiceException: com.vaadin.ui.Table$CacheUpdateException: Error during Table cache update. Additional causes not shown.]
 with root cause

java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer

    at com.example.table_chapter_5_21.TotalColumnGenerator.generateCell(TotalColumnGenerator.java:27)

    at com.example.table_chapter_5_21.TotalColumnGenerator.generateCell(TotalColumnGenerator.java:1)

    at com.vaadin.ui.Table.parseItemIdToCells(Table.java:2334)

    at com.vaadin.ui.Table.getVisibleCellsNoCache(Table.java:2195)

    at com.vaadin.ui.Table.refreshRenderedCells(Table.java:1717)

    at com.vaadin.ui.Table.attach(Table.java:4244)

    at com.vaadin.ui.AbstractComponent.setParent(AbstractComponent.java:484)

    at com.vaadin.ui.AbstractComponentContainer.addComponent(AbstractComponentContainer.java:210)

    at com.vaadin.ui.AbstractOrderedLayout.addComponent(AbstractOrderedLayout.java:90)

    at com.example.table_chapter_5_21.TableUI.init(TableUI.java:352)

    at com.vaadin.ui.UI.doInit(UI.java:645)

    at com.vaadin.server.communication.UIInitHandler.getBrowserDetailsUI(UIInitHandler.java:222)

    at com.vaadin.server.communication.UIInitHandler.synchronizedHandleRequest(UIInitHandler.java:74)

    at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)

    at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1406)

    at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:305)

    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)

    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)

    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)

    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)

    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)

    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)

    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)

    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)

    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)

    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)

    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)

    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)

    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

    at java.lang.Thread.run(Thread.java:745)

There’s a complain about a ClassCastException on this line:

Double price = (Double) source.getItem(itemId).getItemProperty(this.priceId).getValue(); Inside the

generateCell()

method of the

TotalColumnGenerator
class
. Why this error?
price
has a Double value, shouldn’t it work?

Anyway, that (
prop.getType().equals(Double.class)
) is inside the Book of Vaadin example, I took it from there, should I change it to (
prop

instanceof Double
)?

Doesn’t matters anymore, I was able to find the issues:


String priceStr = String.format("%.2

f
[i]

[/i]
€", price);
There’s an error missing in the format of the string.

Anyway, I have changed that
…getClass().equals(…)
to an
instanceof
statament.