在 RenderRequestImpl/ActionRequestImpl 建構時:
_ses = new PortletSessionImpl(_req.getSession(), _portletName, _portletCtx);
_req.getSession() 取得的是 Portal System 全域的 HttpSession。因此:
getSession() 或 getPortletSession(),拿到的都是同一個 Portal 級 Session 物件。request.getSession()Liferay 提供 getPortletSession(),但開發者慣用 getSession() 導致無法隔離屬性作用域。
PortletServletRequest 缺少 getSession(boolean) 導致 NPEPortletRequestDispatcherImpl.include() 產生 PortletServletRequest 時:
public PortletServletRequest(HttpServletRequest req, ...) {
super(req);
_ses = req.getSession(); // 仍是 Portal Session
}
它實作了 getSession() 但未實作 getSession(boolean create)。當 JSP/Servlet 呼叫 request.getSession(true) 時,父類 ApplicationHttpRequest 邏輯會嘗試在當前 Web App Context 尋找/建立 Session,卻只能在 Portal Context 找到,導致 localSession == null 拋出 NullPointerException。
ApplicationHttpRequest.getSession(true)
→ context.getManager().findSession(other.getId()) // Portal Context 找不到當前 Web App 的 Session
→ localSession 為 null
→ localSession.access() → NPE
request.getPortletSession() 並指定 PORTLET_SCOPE / APPLICATION_SCOPE。request.getSession(true)。PortletServletRequest 實作完整 Session 介面。