Search code examples
servletsservlet-listeners

Value of the servlet attribute if the attribute was replaced


This is from the book I am reading:

Given this code from an otherwise valid HttpServlet that has also been registered as a ServletRequestAttributeListener:

public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
         req.setAttribute(“a”, “b”);
         req.setAttribute(“a”, “c”);
          req.removeAttribute(“a”);
}
        public void attributeAdded(ServletRequestAttributeEvent ev) {
        System.out.print(“ A:” + ev.getName() + “->” + ev.getValue());
}
       public void attributeRemoved(ServletRequestAttributeEvent ev) {
       System.out.print(“ M:” + ev.getName() + “->” + ev.getValue());
}
       public void attributeReplaced(ServletRequestAttributeEvent ev) {
       System.out.print(“ P:” + ev.getName() + “->” + ev.getValue());
}

What logging output is generated?

And answer is:

C. A:a->b P:a->b M:a->c

And explanation from book is:

Tricky! The getValue method returns the OLD value of the attribute if the attribute was replaced.

My question is how this could be? Particularly this part of sequence is not clear to me: P:a->b Why would it be once again P:a->b instead of P:a->c?


Solution

  • I found explanation:

    The getName() method returns the String name of the attribute that triggered the event. The getValue() method returns the object value of the attribute that triggered the event. Watch out! It returns the old value, not the new one. In other words, it returns the value the attribute had BEFORE the change that triggered the event!

    So it is doing what I thought it should do just not in the order I was expecting (first to change value then to trigger event).

    Even more elaborate explanation is this one:

    Just to clarify this output, can we call them "Added", "Replaced" and "Removed" so we're looking at this:

    Added:a->b Replaced:a->b Removed:a->c

    Now the question is why does Replaced return "b" for the value instead of "c"?

    The simple answer is because that's what the docs say it should do: http://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestAttributeListener.html

    void attributeReplaced(ServletRequestAttributeEvent srae) Receives notification that an attribute has been replaced on the ServletRequest. Parameters: srae - the ServletRequestAttributeEvent containing the ServletRequest and the name and (old) value of the attribute that was replaced

    Now maybe the more interesting question is why are they doing this?

    Well usually APIs like this are designed to pass you the old value, because you always have the option to ask for the current value in the callback. So if they pass you the old value - you have more information available to you than if they just passed in the current value. (There's no way to ask "what value did this attribute use to have?" after it's gone).

    So with this API design you could write a listener than took some action whenever the "a:b" was removed - either by an explicit remove call or by replacing it with another value. If they only passed in the new value, you couldn't write that listener (without storing the values that were added yourself).

    Hope that helps make it clearer why it's this way.