Aggregation not working in Table

I’m using Cuba 6.9.7 version in my project.

I do have an entity called Infrastructure and its composition entity as Reading. I want to show a aggregated value from Reading in Infrastructure table. I’m using Aggregated property in column, but when I enable aggregation for this column i’m getting class cast exception.

java.lang.ClassCastException: java.lang.String cannot be cast to com.haulmont.chile.core.model.MetaPropertyPath
	at com.haulmont.cuba.gui.xml.layout.loaders.AbstractTableLoader.loadAggregation(AbstractTableLoader.java:433)
	at com.haulmont.cuba.gui.xml.layout.loaders.AbstractTableLoader.loadColumn(AbstractTableLoader.java:422)
	at com.haulmont.cuba.gui.xml.layout.loaders.AbstractTableLoader.loadColumns(AbstractTableLoader.java:248)
	at com.haulmont.cuba.gui.xml.layout.loaders.AbstractTableLoader.loadComponent(AbstractTableLoader.java:141)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponents(ContainerLoader.java:37)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponentsAndExpand(ContainerLoader.java:89)
	at com.haulmont.cuba.gui.xml.layout.loaders.GroupBoxLayoutLoader.loadComponent(GroupBoxLayoutLoader.java:62)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponents(ContainerLoader.java:37)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponentsAndExpand(ContainerLoader.java:89)
	at com.haulmont.cuba.gui.xml.layout.loaders.AbstractBoxLoader.loadComponent(AbstractBoxLoader.java:46)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponents(ContainerLoader.java:37)
	at com.haulmont.cuba.gui.xml.layout.loaders.ContainerLoader.loadSubComponentsAndExpand(ContainerLoader.java:89)
	at com.haulmont.cuba.gui.xml.layout.loaders.WindowLoader.loadComponent(WindowLoader.java:80)
	at com.haulmont.cuba.gui.WindowManager.createWindow(WindowManager.java:575)
	at com.haulmont.cuba.gui.WindowManager.openEditor(WindowManager.java:874)
	at com.haulmont.cuba.web.WebWindowManager.openEditor(WebWindowManager.java:178)
	at com.haulmont.cuba.gui.components.WindowDelegate.openEditor(WindowDelegate.java:260)
	at com.haulmont.cuba.web.gui.WebWindow.openEditor(WebWindow.java:497)
	at com.haulmont.cuba.gui.components.actions.EditAction.internalOpenEditor(EditAction.java:274)
	at com.haulmont.cuba.gui.components.actions.EditAction.actionPerform(EditAction.java:223)
	at com.haulmont.cuba.web.gui.components.WebAbstractTable.handleClickAction(WebAbstractTable.java:875)
	at com.haulmont.cuba.web.gui.components.WebAbstractTable.lambda$initComponent$90fa93c2$1(WebAbstractTable.java:760)
	at sun.reflect.GeneratedMethodAccessor173.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:200)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:163)
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1037)
	at com.vaadin.ui.Table.handleClickEvent(Table.java:3175)
	at com.vaadin.ui.Table.changeVariables(Table.java:2952)
	at com.haulmont.cuba.web.toolkit.ui.CubaTable.changeVariables(CubaTable.java:280)
	at com.haulmont.cuba.web.toolkit.ui.CubaGroupTable.changeVariables(CubaGroupTable.java:305)
	at com.vaadin.server.communication.ServerRpcHandler.changeVariables(ServerRpcHandler.java:623)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:470)
	at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:413)
	at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
	at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:90)
	at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
	at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1435)
	at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:361)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:324)
	at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:210)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:107)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:73)
	at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

And below is my table xml.

<table id="infrastructureTable"
                       align="BOTTOM_LEFT"
                       contextMenuEnabled="false"
                       height="408px"
                       responsive="true"
                       stylename="infrastructureTable"
                       width="100%" aggregatable="true">
                    <actions>
                        <action id="create"/>
                        <action id="edit"/>
                        <action id="remove"/>
                        <action id="refresh"/>
                    </actions>
                    <columns>
                        <column id="infrastructureType"/>
                        <column id="location"/>
                        <column id="licenseLine"/>
                        <column id="serviceDate"/>
                        <column id="deficiencyTier"/>
                        <column id="trafficLight"/>
                        <column id="infrastructure.readings.serviceDate">
                            <aggregation type="MAX"/>
                        </column>
                    </columns>
                    <rows datasource="infrastructureDs"/>
                    <rowsCount/>
                    <buttonsPanel>
                        <button action="infrastructureTable.create"
                                stylename="primary"/>
                        <button action="infrastructureTable.edit"
                                stylename="friendly"/>
                        <button id="removeBtn"
                                action="infrastructureTable.remove"
                                stylename="danger"/>
                        <button id="refreshButton"
                                caption="Refresh"
                                icon="REFRESH"
                                invoke="onRefreshButtonClick"
                                stylename="refreshBtn"/>
                    </buttonsPanel>
                </table>

What wrong I’m doing?

Thanks,
Hari

Hello @harikrishnadhas.k1

If I understood correctly from the above message, then the Infrastructure entity is related to the Reading entity as One-to-Many composition. Then you need to change the identifier for the aggregated column to readings. After that, the array of Reading class instance names associated with the current Infrastructure entity will be displayed in the readings column.

In order to show the maximum serviceDate value as an aggregated value, you need to set an AggregationStrategy for readings column:

<column id="readings">
    <aggregation strategyClass="com.company.sample.web.screens.infrastructure.ReadingServiceDateAggregation"/>
</column>

ReadingServiceDateAggregation.java

public class ReadingServiceDateAggregation implements AggregationStrategy<List<Reading>, Date> {

    @Override
    public Date aggregate(Collection<List<Reading>> propertyValues) {
        return propertyValues.stream()
                .flatMap(Collection::stream)
                .map(Reading::getServiceDate)
                .max(Date::compareTo)
                .orElse(null);
    }

    @Override
    public Class<Date> getResultClass() {
        return Date.class;
    }
}

Regards,
Gleb

Hi @durygin,

Thanks for the Support, Appreciate your quick reply.

I tried it and got the results. Unfortunately it is not the result which I was expecting for. It shown me an additional row for Aggregation. However, I want to show the aggregated value (MAX of Service Date for each row)

I have an idea of creating a transient field for service date in Infrastructure entity and get the Max of Date. Let me know if that would be fine or any other efficient way is available in the framework.

Thanks Again,
Hari

Do you need this field (MAX of Service Date for current Infrastructure) only for display in DataGrid component or do you use it in other places in your program?

I need this only for display in DataGrid.

Then it will be enough for you to use the generator for readings column.

XML

<column id="readings" generator="generateReadingsColumn"/>

InfrastructureBrowse

public class InfrastructureBrowse extends AbstractLookup {

    @Inject
    private ComponentsFactory componentsFactory;

    public Component generateReadingsColumn(Infrastructure infrastructure) {
        Label label = componentsFactory.createComponent(Label.class);
        label.setValue(getMaxDate(infrastructure));
        return label;
    }

    private Date getMaxDate(Infrastructure infrastructure) {
        List<Reading> readings = infrastructure.getReadings();
        if (readings != null) {
            return readings.stream()
                    .map(Reading::getServiceDate)
                    .max(Date::compareTo)
                    .orElse(null);
        }
        return null;
    }
}

OK Thank you, That works!

Happy New Year!!