adessoSE/budgeteer

Budget month / week report page crash on past data

tinne opened this issue · 2 comments

tinne commented

Historical data of 2016 or 2017 leads to a deterministic crash for all Budget Week and Month reports with the following stack trace. This might be a migration issue, as data from 2018+ is not affected. Interestingly, historical data from 2015 is not affected either.

18:00:04.900 [https-jsse-nio-8337-exec-2] ERROR o.a.wicket.DefaultExceptionMapper - Unexpected error occurred
org.apache.wicket.WicketRuntimeException: Error attaching this container for rendering: [WebMarkupContainer [Component id = hoursTable]]
	at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1848)
	at org.apache.wicket.Component.onBeforeRender(Component.java:3916)
	at org.apache.wicket.Component.internalBeforeRender(Component.java:950)
	at org.apache.wicket.Component.beforeRender(Component.java:1018)
	at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1836)
	at org.apache.wicket.Component.onBeforeRender(Component.java:3916)
	at org.apache.wicket.Component.internalBeforeRender(Component.java:950)
	at org.apache.wicket.Component.beforeRender(Component.java:1018)
	at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1836)
	at org.apache.wicket.Component.onBeforeRender(Component.java:3916)
	at org.apache.wicket.Page.onBeforeRender(Page.java:801)
	at org.apache.wicket.Component.internalBeforeRender(Component.java:950)
	at org.apache.wicket.Component.beforeRender(Component.java:1018)
	at org.apache.wicket.Component.internalPrepareForRender(Component.java:2236)
	at org.apache.wicket.Page.internalPrepareForRender(Page.java:242)
	at org.apache.wicket.Component.render(Component.java:2325)
	at org.apache.wicket.Page.renderPage(Page.java:1018)
	at org.apache.wicket.request.handler.render.WebPageRenderer.renderPage(WebPageRenderer.java:124)
	at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:236)
	at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:175)
	at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:895)
	at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)
	at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:265)
	at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:222)
	at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:293)
	at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:261)
	at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203)
	at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:284)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	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.RuntimeException: An error occurred while getting the model object for Component: [ListView [Component id = list, page = org.wickedsource.budgeteer.web.pages.budgets.monthreport.multi.MultiBudgetMonthReportPage, path = table:hoursTable:list, type = org.apache.wicket.markup.html.list.ListView, isVisible = true, isVersioned = true]]
	at org.apache.wicket.Component.getDefaultModelObject(Component.java:1651)
	at org.apache.wicket.markup.html.list.ListView.getViewSize(ListView.java:218)
	at org.apache.wicket.markup.html.list.ListView.onPopulate(ListView.java:472)
	at org.apache.wicket.markup.repeater.AbstractRepeater.onBeforeRender(AbstractRepeater.java:124)
	at org.apache.wicket.Component.internalBeforeRender(Component.java:950)
	at org.apache.wicket.Component.beforeRender(Component.java:1018)
	at org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1836)
	... 86 common frames omitted
Caused by: java.lang.NullPointerException: null
	at org.wickedsource.budgeteer.MoneyUtil.getCentsWithTaxes(MoneyUtil.java:112)
	at org.wickedsource.budgeteer.service.record.PlanAndWorkRecord.<init>(PlanAndWorkRecord.java:79)
	at org.wickedsource.budgeteer.persistence.record.ListJoiner.joinMonthlyToPlanAndWorkRecords(ListJoiner.java:104)
	at org.wickedsource.budgeteer.service.record.RecordJoiner.joinMonthlyWithTax(RecordJoiner.java:116)
	at org.wickedsource.budgeteer.service.record.RecordService.getMonthlyAggregationForBudgetsWithTax(RecordService.java:186)
	at org.wickedsource.budgeteer.service.record.RecordService$$FastClassBySpringCGLIB$$6dc8b691.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
	at org.wickedsource.budgeteer.service.record.RecordService$$EnhancerBySpringCGLIB$$16df354d.getMonthlyAggregationForBudgetsWithTax(<generated>)
	at WICKET_org.wickedsource.budgeteer.service.record.RecordService$$FastClassByCGLIB$$6dc8b691.invoke(<generated>)
	at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.apache.wicket.proxy.LazyInitProxyFactory$AbstractCGLibInterceptor.intercept(LazyInitProxyFactory.java:350)
	at WICKET_org.wickedsource.budgeteer.service.record.RecordService$$EnhancerByCGLIB$$8bf167e1.getMonthlyAggregationForBudgetsWithTax(<generated>)
	at org.wickedsource.budgeteer.web.pages.budgets.components.weekreporttable.BudgetsMonthlyAggregatedRecordsModel.load(BudgetsMonthlyAggregatedRecordsModel.java:37)
	at org.wickedsource.budgeteer.web.pages.budgets.components.weekreporttable.BudgetsMonthlyAggregatedRecordsModel.load(BudgetsMonthlyAggregatedRecordsModel.java:13)
	at org.apache.wicket.model.LoadableDetachableModel.getObject(LoadableDetachableModel.java:135)
	at org.apache.wicket.Component.getDefaultModelObject(Component.java:1646)
	... 92 common frames omitted

This issue occurs because of a missing tax rate in the historical data of 2016 and 2017.
In our opinion, this isn't a migration issue. That's why @czarnecki will add a Null-Check inside the constructor.

This check will prevent a calculation with a null value. Instead of the null value of the bean, the calculation will be done with a tax rate of zero.

tinne commented

OK for the Entity, not OK for the model object:

Just checked the data - is is possible that a null value is displayed as 0,0 in the Edit Contract view? It should better be displayed as an empty string to hint the user that the value is missing.

Making the input field obligatory is fine with me, but then the user should be forced to enter something starting from empty string, not from a (mostly) wrong value, which is easier to overlook when entering data.