HttpSession setAttribute 并不总是插入新对象
HttpSession setAttribute doesn't always insert new object
我正在努力从 WLS10g 和 JavaEE6 升级到 WLS12c 和 JavaEE7。
我注意到 HttpSession.setAttribute
的工作方式有所不同。在 WLS10 中,任何已经存储在某个键下的对象总是会被替换。
在 WLS12 中,如果 newObject.equals(oldObject)
,则不会替换对象。
这对我们来说是个问题,因为应用程序有这样的对象:
class ValueObject {
int key;
String data;
@Override
public int hashCode()
{
return key;
}
boolean equals(Object o) {
if (o == null || (o instanceof ValueObject) == false) {
return false;
}
ValueObject otherObject = (ValueObject)o;
/* Return true if the keys are equal, even though the data may differ */
return key == otherObject.key;
}
}
ValueObject 通过跨越多个网页的工作流程进行修改。中间值存储在 HTTPSession
中,并在工作流结束时将修改后的值写入数据库。
在servlet中有这样的代码(成员实际上是通过getters/setters修改的,但是我简化了以减少问题中的代码量):
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
HttpSession session = request.getSession();
ValueObject newValue = new ValueObject();
newValue.key = Integer.parseInt(request.getParameter("key"));
newValue.data = request.getParameter("data");
session.setAttribute("value", newValue);
...
newValue.key
未修改,而 newValue.data
具有新值。
WLS12 中 HttpSession
的修改行为打破了这种模式 - 当从会话中检索对象时,我们从第一步获得 data
,因为当我们尝试存储更新版本。
我们可以通过更改所有更新来解决此问题:
session.setAttribute("value", newValue);
到
session.removeAttribute("value");
session.setAttribute("value", newValue);
但是,有 100 多个 servlet,因此工作量很大。而且解决方法既难看又容易出错,因为程序员在编写代码时需要跟踪一件事。
有什么方法可以配置 WLS12c 以使用对象总是被 HttpSession.setAttribute()
替换的旧行为?
更新 2015-09-30:
向 Oracle 提交错误报告。我已经尝试过 wero 建议的过滤器想法。似乎 Weblogic 期望从过滤器链下来的对象是 class weblogic.server.internal.ServletRequestImpl
,因为当我包装它并将包装器发送到过滤器链时,我从内部 Weblogic class 得到了一个 ClassCastException ].
我也按照 Gimby 的建议检查了配置选项。我找不到该会话的任何适用选项。我们部署到单个服务器并使用 memory
作为会话持久性设置。
更新 2016-02-03:
Oracle 已关闭错误报告 "Not a bug"。
不是您关于变通方法的问题的答案,但 Session.setAttribute
的 Javadoc 对行为非常清楚:
Binds an object to this session, using the name specified. If an
object of the same name is already bound to the session, the object is
replaced.
所以您可以随时提交错误报告。
解决方法可以使用过滤器来安装包装的 HttpServletRequest
,其中 returns 包装的 HttpSession
覆盖 setAttribute
并实施先替换后设置逻辑.
由于 Oracle 关闭了错误报告 "not a bug" 我决定实施解决方法。
我查看了对 HttpSession.setAttribute
的所有调用,并确定了哪些调用使用了可能触发错误的对象。
那些地方我都换了
session.setAttribute(key, newValue);
和
session.removeAttribute(key);
session.setAttribute(key, newValue);
连同注释解释为什么需要额外的行。
我正在努力从 WLS10g 和 JavaEE6 升级到 WLS12c 和 JavaEE7。
我注意到 HttpSession.setAttribute
的工作方式有所不同。在 WLS10 中,任何已经存储在某个键下的对象总是会被替换。
在 WLS12 中,如果 newObject.equals(oldObject)
,则不会替换对象。
这对我们来说是个问题,因为应用程序有这样的对象:
class ValueObject {
int key;
String data;
@Override
public int hashCode()
{
return key;
}
boolean equals(Object o) {
if (o == null || (o instanceof ValueObject) == false) {
return false;
}
ValueObject otherObject = (ValueObject)o;
/* Return true if the keys are equal, even though the data may differ */
return key == otherObject.key;
}
}
ValueObject 通过跨越多个网页的工作流程进行修改。中间值存储在 HTTPSession
中,并在工作流结束时将修改后的值写入数据库。
在servlet中有这样的代码(成员实际上是通过getters/setters修改的,但是我简化了以减少问题中的代码量):
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
HttpSession session = request.getSession();
ValueObject newValue = new ValueObject();
newValue.key = Integer.parseInt(request.getParameter("key"));
newValue.data = request.getParameter("data");
session.setAttribute("value", newValue);
...
newValue.key
未修改,而 newValue.data
具有新值。
WLS12 中 HttpSession
的修改行为打破了这种模式 - 当从会话中检索对象时,我们从第一步获得 data
,因为当我们尝试存储更新版本。
我们可以通过更改所有更新来解决此问题:
session.setAttribute("value", newValue);
到
session.removeAttribute("value");
session.setAttribute("value", newValue);
但是,有 100 多个 servlet,因此工作量很大。而且解决方法既难看又容易出错,因为程序员在编写代码时需要跟踪一件事。
有什么方法可以配置 WLS12c 以使用对象总是被 HttpSession.setAttribute()
替换的旧行为?
更新 2015-09-30:
向 Oracle 提交错误报告。我已经尝试过 wero 建议的过滤器想法。似乎 Weblogic 期望从过滤器链下来的对象是 class weblogic.server.internal.ServletRequestImpl
,因为当我包装它并将包装器发送到过滤器链时,我从内部 Weblogic class 得到了一个 ClassCastException ].
我也按照 Gimby 的建议检查了配置选项。我找不到该会话的任何适用选项。我们部署到单个服务器并使用 memory
作为会话持久性设置。
更新 2016-02-03:
Oracle 已关闭错误报告 "Not a bug"。
不是您关于变通方法的问题的答案,但 Session.setAttribute
的 Javadoc 对行为非常清楚:
Binds an object to this session, using the name specified. If an object of the same name is already bound to the session, the object is replaced.
所以您可以随时提交错误报告。
解决方法可以使用过滤器来安装包装的 HttpServletRequest
,其中 returns 包装的 HttpSession
覆盖 setAttribute
并实施先替换后设置逻辑.
由于 Oracle 关闭了错误报告 "not a bug" 我决定实施解决方法。
我查看了对 HttpSession.setAttribute
的所有调用,并确定了哪些调用使用了可能触发错误的对象。
那些地方我都换了
session.setAttribute(key, newValue);
和
session.removeAttribute(key);
session.setAttribute(key, newValue);
连同注释解释为什么需要额外的行。