Home
Analytics
POJO ODA How to create nested data/tables
locutuz
<p>Hello everybody,</p>
<p> </p>
<p>I tried to create a report using the new POJO data source.</p>
<p>I get stuck when I have nested objects, i.e. a pojo that includes another pojo.</p>
<p> </p>
<p>The attached example includes the POJOs Man.java and Car.java.</p>
<p>A "Man" has a name and some "Car"s, where a "Car" has a name and a year.</p>
<p> </p>
<p>
</p>
<p>BMW-fan Model: Year</p>
<p>
</p>
<p> BMW 1980</p>
<p> BMW 1981</p>
<p> BMW 1985</p>
<p> </p>
<p> </p>
<p>Porsche-freak Model: Year</p>
<p>
</p>
<p> Porsche1 1960</p>
<p> Porsche2 1963</p>
<p> Porsche1 1966</p>
<p>
</p>
<p> </p>
<p>I don't know what to do that the report shows this nested table.</p>
<p> </p>
<p>Can anybody help me?</p>
<p> </p>
<p>Thanks a lot.</p>
<p> </p>
<p>Regards,</p>
<p>Sebastian</p>
Find more posts tagged with
Comments
mwilliams
Here's your project with another class added to create a second data set for the cars. The class grabs an instance of the Men with Cars data set and steps through it to find the man referenced by the data set parameter. From there, the list of cars is iterated through and returned to BIRT as the result set. In the report, this second data set is embedded into the first in the report with the name of the man in the outer table passed through to the inner POJO through a data set parameter for the new cars data set to be able to grab the correct list of cars.<br><br>There are probably other ways to do it, but this will work. Hope it helps.
locutuz
<p>Hi Michael,</p>
<p> </p>
<p>thanks for your answer!</p>
<p>Unfortunately I can't run your suggestion, because I get the error below when I just drag the MenWithCars dataset onto an report and want to get it displayed. The preview of the dataset looks fine, but at runtime it seems, that birt misses the Cars class.</p>
<p>How do I make the class visible for birt?</p>
<p> </p>
<p>Thanks in advance. :-)</p>
<p> </p>
<p>Here's the exception:</p>
<p> </p>
<div> </div>
<div>
<div style="color:rgb(255,0,0);font-family:sans-serif;font-size:13.3333330154419px;">Table (id = 83):</div>
<div style="color:rgb(255,0,0);font-family:sans-serif;font-size:13.3333330154419px;"><span>- </span>A report document error occurred when loading: Result Data.<br>
Failed to load class "men.Car" for "Java Object" type column "Cars". please make sure class "men.Car" is included in the class loading path of BIRT engine.<br>
men.Cardata.engine.LoadReportDocumentError ( 1 time(s) )<br>
detail : org.eclipse.birt.report.engine.api.EngineException: A report document error occurred when loading: Result Data.<br>
Failed to load class "men.Car" for "Java Object" type column "Cars". please make sure class "men.Car" is included in the class loading path of BIRT engine.<br>
men.Car<br>
at org.eclipse.birt.report.engine.executor.ExecutionContext.addException(ExecutionContext.java:1245)<br>
at org.eclipse.birt.report.engine.executor.ExecutionContext.addException(ExecutionContext.java:1224)<br>
at org.eclipse.birt.report.engine.internal.document.v4.ReportItemExecutor.executeQuery(ReportItemExecutor.java:429)<br>
at org.eclipse.birt.report.engine.internal.document.v4.TableItemExecutor.doExecute(TableItemExecutor.java:72)<br>
at org.eclipse.birt.report.engine.internal.document.v4.ReportItemExecutor.execute(ReportItemExecutor.java:294)<br>
at org.eclipse.birt.report.engine.internal.document.v4.ContainerExecutor.prepareChildExecutor(ContainerExecutor.java:226)<br>
at org.eclipse.birt.report.engine.internal.document.v4.ContainerExecutor.hasNextChild(ContainerExecutor.java:110)<br>
at org.eclipse.birt.report.engine.internal.executor.wrap.WrappedReportItemExecutor.hasNextChild(WrappedReportItemExecutor.java:86)<br>
at org.eclipse.birt.report.engine.internal.executor.wrap.WrappedReportItemExecutor.hasNextChild(WrappedReportItemExecutor.java:86)<br>
at org.eclipse.birt.report.engine.api.impl.RenderTask$ReportExecutorWrapper.hasNextChild(RenderTask.java:849)<br>
at org.eclipse.birt.report.engine.layout.html.HTMLPageLM$1.hasNextChild(HTMLPageLM.java:68)<br>
at org.eclipse.birt.report.engine.layout.html.HTMLBlockStackingLM.layoutNodes(HTMLBlockStackingLM.java:62)<br>
at org.eclipse.birt.report.engine.layout.html.HTMLPageLM.layout(HTMLPageLM.java:92)<br>
at org.eclipse.birt.report.engine.layout.html.HTMLReportLayoutEngine.layout(HTMLReportLayoutEngine.java:100)<br>
at org.eclipse.birt.report.engine.api.impl.RenderTask$PageRangeRender.render(RenderTask.java:717)<br>
at org.eclipse.birt.report.engine.api.impl.RenderTask.render(RenderTask.java:321)<br>
at org.eclipse.birt.report.service.ReportEngineService.renderReport(ReportEngineService.java:1555)<br>
at org.eclipse.birt.report.service.BirtViewerReportService.getPage(BirtViewerReportService.java:204)<br>
at org.eclipse.birt.report.service.actionhandler.AbstractGetPageActionHandler.doExecution(AbstractGetPageActionHandler.java:237)<br>
at org.eclipse.birt.report.service.actionhandler.AbstractGetPageActionHandler.__execute(AbstractGetPageActionHandler.java:104)<br>
at org.eclipse.birt.report.service.actionhandler.AbstractBaseActionHandler.execute(AbstractBaseActionHandler.java:90)<br>
at org.eclipse.birt.report.soapengine.processor.AbstractBaseDocumentProcessor.__executeAction(AbstractBaseDocumentProcessor.java:47)<br>
at org.eclipse.birt.report.soapengine.processor.AbstractBaseComponentProcessor.executeAction(AbstractBaseComponentProcessor.java:143)<br>
at org.eclipse.birt.report.soapengine.processor.BirtDocumentProcessor.handleGetPage(BirtDocumentProcessor.java:87)<br>
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br>
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)<br>
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)<br>
at java.lang.reflect.Method.invoke(Unknown Source)<br>
at org.eclipse.birt.report.soapengine.processor.AbstractBaseComponentProcessor.process(AbstractBaseComponentProcessor.java:112)<br>
at org.eclipse.birt.report.soapengine.endpoint.BirtSoapBindingImpl.getUpdatedObjects(BirtSoapBindingImpl.java:66)<br>
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br>
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)<br>
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)<br>
at java.lang.reflect.Method.invoke(Unknown Source)<br>
at org.apache.axis.providers.java.RPCProvider.invokeMethod(RPCProvider.java:397)<br>
at org.apache.axis.providers.java.RPCProvider.processMessage(RPCProvider.java:186)<br>
at org.apache.axis.providers.java.JavaProvider.invoke(JavaProvider.java:323)<br>
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)<br>
at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)<br>
at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)<br>
at org.apache.axis.handlers.soap.SOAPService.invoke(SOAPService.java:454)<br>
at org.apache.axis.server.AxisServer.invoke(AxisServer.java:281)<br>
at org.apache.axis.transport.http.AxisServlet.doPost(AxisServlet.java:699)<br>
at org.eclipse.birt.report.servlet.BirtSoapMessageDispatcherServlet.doPost(BirtSoapMessageDispatcherServlet.java:265)<br>
at javax.servlet.http.HttpServlet.service(HttpServlet.java:755)<br>
at org.apache.axis.transport.http.AxisServletBase.service(AxisServletBase.java:327)<br>
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)<br>
at org.eclipse.birt.report.servlet.BirtSoapMessageDispatcherServlet.service(BirtSoapMessageDispatcherServlet.java:122)<br>
at org.eclipse.equinox.http.registry.internal.ServletManager$ServletWrapper.service(ServletManager.java:180)<br>
at org.eclipse.equinox.http.servlet.internal.ServletRegistration.service(ServletRegistration.java:61)<br>
at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:128)<br>
at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:60)<br>
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)<br>
at org.eclipse.equinox.http.jetty.internal.HttpServerManager$InternalHttpServiceServlet.service(HttpServerManager.java:360)<br>
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)<br>
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501)<br>
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:229)<br>
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)<br>
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:428)<br>
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)<br>
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)<br>
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)<br>
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)<br>
at org.eclipse.jetty.server.Server.handle(Server.java:370)<br>
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)<br>
at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:982)<br>
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1043)<br>
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:865)<br>
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)<br>
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)<br>
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:667)<br>
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)<br>
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)<br>
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)<br>
at java.lang.Thread.run(Unknown Source)<br>
Caused by: org.eclipse.birt.data.engine.core.DataException: A report document error occurred when loading: Result Data.<br>
Failed to load class "men.Car" for "Java Object" type column "Cars". please make sure class "men.Car" is included in the class loading path of BIRT engine.<br>
men.Car<br>
at org.eclipse.birt.data.engine.impl.document.viewing.DataSetResultSet.next(DataSetResultSet.java:190)<br>
at org.eclipse.birt.data.engine.impl.document.util.ExprDataReader1.next(ExprDataReader1.java:202)<br>
at org.eclipse.birt.data.engine.impl.document.util.ExprResultSet.next(ExprResultSet.java:181)<br>
at org.eclipse.birt.data.engine.impl.document.ResultIterator.doNext(ResultIterator.java:188)<br>
at org.eclipse.birt.data.engine.impl.document.ResultIterator.<init>(ResultIterator.java:107)<br>
at org.eclipse.birt.data.engine.impl.document.ResultIterator.<init>(ResultIterator.java:77)<br>
at org.eclipse.birt.data.engine.impl.document.QueryResults.getResultIterator(QueryResults.java:263)<br>
at org.eclipse.birt.report.engine.data.dte.QueryResultSet.<init>(QueryResultSet.java:98)<br>
at org.eclipse.birt.report.engine.data.dte.DataPresentationEngine.doExecuteQuery(DataPresentationEngine.java:190)<br>
at org.eclipse.birt.report.engine.data.dte.AbstractDataEngine.execute(AbstractDataEngine.java:275)<br>
at org.eclipse.birt.report.engine.executor.ExecutionContext.executeQuery(ExecutionContext.java:1947)<br>
at org.eclipse.birt.report.engine.internal.document.v4.ReportItemExecutor.executeQuery(ReportItemExecutor.java:412)<br>
... 72 more<br>
Caused by: org.eclipse.birt.data.engine.core.DataException: Failed to load class "men.Car" for "Java Object" type column "Cars". please make sure class "men.Car" is included in the class loading path of BIRT engine.<br>
men.Car<br>
at org.eclipse.birt.data.engine.executor.cache.ResultSetUtil.readResultObject(ResultSetUtil.java:207)<br>
at org.eclipse.birt.data.engine.impl.document.viewing.DataSetResultSet.next(DataSetResultSet.java:177)<br>
... 83 more<br>
Caused by: java.io.IOException: men.Car<br>
at org.eclipse.birt.core.util.IOUtil.readObject(IOUtil.java:638)<br>
at org.eclipse.birt.core.util.IOUtil.readList(IOUtil.java:953)<br>
at org.eclipse.birt.core.util.IOUtil.readObject(IOUtil.java:610)<br>
at org.eclipse.birt.data.engine.executor.cache.ResultObjectUtil.readObject(ResultObjectUtil.java:259)<br>
at org.eclipse.birt.data.engine.executor.cache.ResultSetUtil.readResultObject(ResultSetUtil.java:192)<br>
... 84 more<br>
Caused by: java.lang.ClassNotFoundException: men.Car<br>
at org.eclipse.birt.core.framework.URLClassLoader.findClass1(URLClassLoader.java:188)<br>
at org.eclipse.birt.core.framework.URLClassLoader$1.run(URLClassLoader.java:156)<br>
at org.eclipse.birt.core.framework.URLClassLoader$1.run(URLClassLoader.java:1)<br>
at java.security.AccessController.doPrivileged(Native Method)<br>
at org.eclipse.birt.core.framework.URLClassLoader.findClass(URLClassLoader.java:151)<br>
at java.lang.ClassLoader.loadClass(Unknown Source)<br>
at java.lang.ClassLoader.loadClass(Unknown Source)<br>
at org.eclipse.birt.report.engine.executor.ApplicationClassLoader.loadClass(ApplicationClassLoader.java:79)<br>
at java.lang.Class.forName0(Native Method)<br>
at java.lang.Class.forName(Unknown Source)<br>
at org.eclipse.birt.core.util.IOUtil$1.resolveClass(IOUtil.java:628)<br>
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)<br>
at java.io.ObjectInputStream.readClassDesc(Unknown Source)<br>
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)<br>
at java.io.ObjectInputStream.readObject0(Unknown Source)<br>
at java.io.ObjectInputStream.readObject(Unknown Source)<br>
at org.eclipse.birt.core.util.IOUtil.readObject(IOUtil.java:634)<br>
... 88 more</div>
</div>
locutuz
<p>Okay, I put the MenWithCars.jar file to the Java-projects Java-Build Path -> Add Excternal Jars</p>
<p> </p>
<p>Now the result is displayed as expected.</p>
<p> </p>
<p>Thanks for the help! :-)</p>
<p> </p>
<p>Regards,</p>
<p>Sebastian</p>
mwilliams
Awesome! Glad it's working for you!
Matt Dillenkoffer
<p>Do you have to have two POJO datasets to pull of nested lists. My outer dataset is smart enough to correctly load the nested list without a dataset parameter being passed in. I just don't understand how to use the designer to tell it how to see the attributes of list of child objects. Because the designer sees my list as Java Object.</p>
<p> </p>
<p>I sort of got it working but now because I have two datasets I'm making two data calls when I really only need to make 1.</p>
Matt Dillenkoffer
<p>I figured it out, in my outer dataset java code when I get the data I put the child collection in the appContext Object variable. I cast that to the Map<String, Object> that I knew it was and put the list in it. When the open method for the inner dataset runs it finds the collection it needs in the appContext Then embed the second dataset in to a detail row in the table representing my outer dataset. Whenever I had the child list as a Java Object attribute on my table it broke the report if that attribute were included in the table.</p>
jing.li
<blockquote class="ipsBlockquote" data-author="Matt Dillenkoffer" data-cid="147116" data-time="1489591882">
<div>
<p>I figured it out, in my outer dataset java code when I get the data I put the child collection in the appContext Object variable. I cast that to the Map<String, Object> that I knew it was and put the list in it. When the open method for the inner dataset runs it finds the collection it needs in the appContext Then embed the second dataset in to a detail row in the table representing my outer dataset. Whenever I had the child list as a Java Object attribute on my table it broke the report if that attribute were included in the table.</p>
</div>
</blockquote>
<p> </p>
<p>Hello Matt, </p>
<p> </p>
<p>I am trying to design a similar report with POJO data source. I could not figure out how to do the BIRT report design and how to pass data to render it on run time. </p>
<p> </p>
<p>Could you please explain in details about how to use the appContext Object variable to accomplish it?</p>
<p> </p>
<p>Thank you very much,</p>
<p> </p>
<p>Jing </p>
Matt Dillenkoffer
<p>You have 2 datasets outer and inner. The natural way to do it would be to have outer have a column in it that you want the inner dataset to use as a key to look up the data related to the outer set. The way you make a outer dataset column available to the inner dataset is you use the dataset editor to add a parameter to the inner dataset that references a column in the outer dataset.</p>
<p> </p>
<p>Then in the open method of your inner dataset you grab that parameter like so...</p>
<p> </p>
<p><span style="color:#cc7832;">public void </span><span style="color:#ffc66d;">open</span>(Object appContext<span style="color:#cc7832;">, </span>Map<String<span style="color:#cc7832;">,</span>Object> map){<br><br>
String personId = (String)map.get(<span style="color:#6a8759;">"PersonId"</span>)<span style="color:#cc7832;">;</span></p>
<p> </p>
<p>}</p>
<p> </p>
<p>In that model you wouldn't need to pass any info in the appContext because the the inner dataset uses the parameter PersonId to do some additional service call. This will work but didn't quite fit what I wanted to do because my initial query in my outer dataset got all the data I needed with a single request.</p>
<p> </p>
<p>So I will basically have the same setup as I described before but instead of my inner dataset having to query a service for the inner data it will be passed from the outer dataset to the inner dataset in the appContext. See example code below.</p>
<p>This is a simplified example of what I did.</p>
<p> </p>
<p>Outerdataset:</p>
<p> </p>
<p><span style="color:#cc7832;">public void </span><span style="color:#ffc66d;">open</span>(Object appContext<span style="color:#cc7832;">, </span>Map<String<span style="color:#cc7832;">,</span>Object> map){<br><br>
String <span style="color:#6a8759;">companyId</span> = (String)map.get(<span style="color:#6a8759;">"companyId"</span>)<span style="color:#cc7832;">;</span><br><span style="color:#cc7832;"> List<Team> teams = service.getTeamsByCompanyId(<span style="color:#6a8759;">companyId</span>);</span></p>
<p> Map<String, List<Member>> memberMap = new HashMap<>();</p>
<p> for(Team t : teams){</p>
<p> List<Member> members = t.getMembers();</p>
<p>//note that the key of memberMap is the team ID</p>
<p> memberMap.put(t.getId(), members);</p>
<p> }</p>
<p> ((Map<String,Object) appContext).put("memberMap", memberMap);<br><span style="color:#9876aa;"> iterator </span>= teams.iterator()<span style="color:#cc7832;">;</span><br>
}</p>
<p> </p>
<p>InnerDataset:</p>
<p> </p>
<p><span style="color:#cc7832;">public void </span><span style="color:#ffc66d;">open</span>(Object appContext<span style="color:#cc7832;">, </span>Map<String<span style="color:#cc7832;">,</span>Object> map){<br><br>
String teamId = (String)map.get(<span style="color:#6a8759;">"teamId"</span>)<span style="color:#cc7832;">;</span><br>
Map<String<span style="color:#cc7832;">, </span>Object> appContextDataMap = (Map<String<span style="color:#cc7832;">, </span>Object>) appContext<span style="color:#cc7832;">;</span><br>
Map<String<span style="color:#cc7832;">, </span>List<Member>> memberMap = (Map<String<span style="color:#cc7832;">, </span>List<Member>>)appContextDataMap.get("memberMap")<span style="color:#cc7832;">;</span><br>
List<Member> memberList = memberMap.get(teamId)<span style="color:#cc7832;">;</span><br><span style="color:#9876aa;">iterator </span>= memberList.iterator()<span style="color:#cc7832;">;</span><br>
}</p>
<p> </p>
<p> </p>
<p> </p>
<p>That's it! As the outer dataset iterates over teams each new team will cause the inner dataset open method to be called and the teamId will be made available to the open method because of the teamId parameter you configured in your inner data set editor to reference the teamId column in the outer dataset. When the outer dataset runs it puts the whole memberMap into the appContext and the teamId is used as a key to pull the right list out of the map. hth</p>
jing.li
<p>Hello Matt, </p>
<p> </p>
<p>Thank you very much for the details of the POJO outer and inner data sets implementation. </p>
<p> </p>
<p>Are "<span style="color:rgb(106,135,89);font-family:'Source Sans Pro', sans-serif;">companyId</span>" and "<span style="color:rgb(40,40,40);font-family:'Source Sans Pro', sans-serif;">memberMap</span>" the outer dataset parameters? I do not know how to connect the two datasets implementation to the birt report tables parameters binding. </p>
<p> </p>
<p>Could you please share your BIRT report design for this example?</p>
<p> </p>
<p>Thanks again, </p>
<p> </p>
<p>Jing</p>