views:

3939

answers:

3

Is there any way under spring 3.0 to access the HttpSession without including it in the method signature? What I really want to do is be able to pass in values from an HttpSession that CAN BE null.

Something like this:

@RequestMapping("/myHomePage")
public ModelAndView show(UserSecurityContext ctx) {}

instead of this:

@RequestMapping("/myHomePage")
public ModelAndView show(HttpSession session) {
      UserSecurityContext ctx = (UserSecurityContext) session.getAttribute("userSecurityCtx");
}
+2  A: 

Yes, you can.

@SessionAttributes("userSecurityContext")
public class UserSecurityContext {
}

@RequestMapping("/myHomePage")
public String show(@ModelAttribute("userSecurityContext") UserSecurityContext u) {
    // code goes here.
}

See for details:

  1. http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/SessionAttributes.html

  2. http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html

uthark
Thanks for the response. I'm adding my security context initially with session.putAttribute(). When I try your code, the context object is null.
Mark
Sorry, this did end up working when I added @SessionAttributes("userSecurityContext") to the controller. Simply adding it to the actual UserSecurityContext pojo didn't do anything for me. However an exception is thrown from Spring when the attribute is null which is what I'm trying to avoid. org.springframework.web.HttpSessionRequiredException: Session attribute 'userSecurityContext' required - not found in session
Mark
+2  A: 

The @SessionAttribute annotation mentioned by @uthark is not suitable for this task - I thought it was too, but a bit of reading shows otherwise:

Session attributes as indicated using this annotation correspond to a specific handler's model attributes, getting transparently stored in a conversational session. Those attributes will be removed once the handler indicates completion of its conversational session. Therefore, use this facility for such conversational attributes which are supposed to be stored in the session temporarily during the course of a specific handler's conversation.

For permanent session attributes, e.g. a user authentication object, use the traditional session.setAttribute method instead. Alternatively, consider using the attribute management capabilities of the generic WebRequest interface.

In other words, @SessionAttribute is for storing conversation MVC-model objects in the session (as opposed to storing them as request attributes). It's not intended for using with arbitrary session attributes. As you discovered, it only works if the session attribute is always there.

I'm not aware of any other alternative, I think you're stuck with HttpSession.getAttribute()

skaffman
I actually ended up using part of @uthark solution. To guard against exceptions caused by a null user context object, I put a ServletFilter in front to make sure it was populated. I'm ok with this solution for this particular workflow but it does seem weird that you can't handle a null value yourself instead of Spring dealing with it for you.Thanks everyone for the help and insight.
Mark
@Mark: It is seem odd, yes.
skaffman
+1  A: 

You can use a RequestContextHolder:

class SecurityContextHolder {
    public static UserSecurityContext currentSecurityContext() {
        return (UserSecurityContext) 
            RequestContextHolder.currentRequestAttributes()
            .getAttribute("userSecurityCtx", RequestAttributes.SCOPE_SESSION));
    }
}
...
@RequestMapping("/myHomePage")           
public ModelAndView show() {           
    UserSecurityContext ctx = SecurityContextHolder.currentSecurityContext();
}

For cross-cutting concerns such as security this approach is better because you doesn't need to modify your controller signatures.

axtavt
I kind of like this solution also. It's somewhat similar to a ThreadLocal pattern. Thanks!
Mark