HttpSession setAttribute doesn't always insert

2019-03-30 21:50发布

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".

2条回答
淡お忘
2楼-- · 2019-03-30 22:15

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.

查看更多
Luminary・发光体
3楼-- · 2019-03-30 22:23

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.

查看更多
登录 后发表回答