A client is running a web app through Tomcat and is getting an unusual NullPointerException in a seemingly innocuous area. As you can see a NullPointerException cannot occur in the constructor of the inner class BookingDetail. And what is this access$300() method and how would it be called? Yes it’s very annoying that I don’t have the line numbers but I cannot replicate this issue.
Here is a snippet of the code from the LeaveCalculator class:
private class BookingDetail {
private Date from;
private Date upto;
private String wpat;
private String pubh;
private BookingDetail(Date from, Date upto, String wpat, String pubh) {
this.from = from;
this.upto = upto;
this.wpat = wpat;
this.pubh = pubh;
}
}
private void calculatePayHoursAndLeaveHoursForLSLHours(Date from, Date upto) {
String pubhMaster = ((LSLLeave) leave).getPublicHoliday().trim();
List<PositionHistory> histories = findHistories(from, upto);
Map<Integer, BookingDetail> table = new HashMap<Integer, BookingDetail>();
for (PositionHistory h : histories) {
BookingDetail position = table.get(h.getEmployment());
if (position == null) {
table.put(h.getEmployment(), new BookingDetail(h.getFromDate(), h.getUpToDate(), h.getWorkPatternCode(), pubhMaster.isEmpty() ? h.getPublicHolidayCode() : pubhMaster));
} else {
if (position.from.after(h.getFromDate()))
position.from = h.getFromDate();
if (position.upto.before(h.getUpToDate()))
position.upto = h.getUpToDate();
}
}
double payHoursTotal = 0;
double leaveHoursTotal = 0;
boolean error = false;
Set<Integer> keys = table.keySet();
for (Integer employment : keys) {
BookingDetail row = table.get(employment);
if (row.from.before(from))
row.from = from;
if (row.upto.after(upto))
row.upto = upto;
calculatePayHoursAndLeaveHours(row, false);
error |= !verifyLeaveHours();
payHoursTotal += payHours;
leaveHoursTotal += leaveHours;
}
leaveHours = error ? WORK_PATTERN_ERROR : leaveHoursTotal;
payHours = payHoursTotal;
BookingDetail lowestEmployment = table.get(employment);
wpat = lowestEmployment.wpat;
pubh = lowestEmployment.pubh;
}
Here is the stack trace:
java.lang.NullPointerException
at com.empower.ess.logic.leave.LeaveCalculator$BookingDetail.access$300(Unknown Source)
at com.empower.ess.logic.leave.LeaveCalculator.calculatePayHoursAndLeaveHoursForLSLHours(Unknown Source)
at com.empower.ess.logic.leave.LeaveCalculator.calculatePayHoursAndLeaveHours(Unknown Source)
at com.empower.ess.logic.leave.LeaveCalculator.calculateAmountToDisplay(Unknown Source)
at com.empower.ess.logic.leave.LeaveCalculator.calculateAmountToDisplay(Unknown Source)
at com.empower.ess.logic.leave.dwr.LeaveTypesLookup.calculateAmount(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1190.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.empower.mawson.core.web.dwr.impl.ExecuteQuery.execute(ExecuteQuery.java:236)
at com.empower.mawson.core.web.dwr.impl.DefaultExecProcessor.handle(DefaultExecProcessor.java:44)
at com.empower.mawson.core.web.dwr.impl.DefaultProcessor.handle(DefaultProcessor.java:79)
at com.empower.mawson.core.web.dwr.AbstractDWRServlet.doPost(AbstractDWRServlet.java:151)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:444)
at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:472)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1286)
at java.lang.Thread.run(Thread.java:619)
The “access$300()” call is a synthetic method which gives access to a private member, here probably “from”, “upto”, “wpat”, or “pubh”. One of those is probably null when looping through your for-each loop. You need to validate that “row.from”, for example, is not null before de-referencing it further.