问题
I am working on an upgrade from WLS10g and JavaEE6 to WLS12c and JavaEE7.
I have noticed a difference on how HttpSession.setAttribute
works. In WLS10, any object already stored under a certain key would always be replaced.
In WLS12 the object is not replaced if newObject.equals(oldObject)
.
This is a problem for us, because the applications have objects like this:
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;
}
}
The ValueObject gets modified through a workflow that spans several web pages. The intermediate values are stored in the HTTPSession
and at the end of the workflow the modified value is written to the database.
In the servlets there is code like this (the members are actually modified through getters/setters, but I am simplifying to reduce the amount of code in the question):
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
is unmodified while newValue.data
has a new value.
The modified behaviour of the HttpSession
in WLS12 breaks this pattern - when the object is retrieved from the session we get the data
from the first step since the object isn't replaced when we try to store updated versions.
We could solve this by changing all updates from:
session.setAttribute("value", newValue);
to
session.removeAttribute("value");
session.setAttribute("value", newValue);
However, there are more than 100 servlets so it is a lot of work. And the workaround is both ugly and prone to errors because the programmers need to keep track of one more thing when writing code.
Is there any way to configure WLS12c to use the old behaviour where the object always is replaced by HttpSession.setAttribute()
?
Update 2015-09-30:
Bug report filed with Oracle. I've tried the filter idea suggested by wero. It seems Weblogic expects the object coming down the filter chain to be of class weblogic.server.internal.ServletRequestImpl
, because when I wrapped it and sent the wrapper down the filter chain I got a ClassCastException from an internal Weblogic class.
I have also checked the configuration options as suggested by Gimby. I could not find any applicable option for the Session. We deploy to a single server and use memory
as session persistence setting.
Update 2016-02-03:
Oracle has closed the bug report as "Not a bug".
回答1:
Since Oracle closed the bug report as "not a bug" I decided to implement the workaround.
I went through all calls to HttpSession.setAttribute
and identified which calls used an object that potentially could trigger the bug.
In those places I replaced
session.setAttribute(key, newValue);
with
session.removeAttribute(key);
session.setAttribute(key, newValue);
along with a comment explaining why the extra line was needed.
回答2:
Not an answer to your question about a workaround, but the Javadoc of Session.setAttribute
is very clear about the behaviour:
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.
So you could always file a bugreport.
A workaround could use a Filter to install a wrapped HttpServletRequest
which returns a wrapped HttpSession
which overrides setAttribute
and implements the replace-then-set-logic.
来源:https://stackoverflow.com/questions/32839048/httpsession-setattribute-doesnt-always-insert-new-object