Alireza Fattahi
Alireza Fattahi

Reputation: 45603

Struts 2 + Spring put a managed spring bean in session

Consider an Struts 2 + Spring 4 project.

For each login the User object is put in session. As a very simple action it will look

public class LoginProcess implements ServletRequestAware {

  @Inject
  private AuthenticationServices authenticationServices;

  public String execute() {
    //The login method makes a new User and fills its setters
    User newUser = authenticationServices.login(....);
    getServletRequest().getSession().setAttribute("USER_SESSION", user);
  }
}

As we manually make a new User object so it is not managed spring bean, and we can't use spring features in User class: @Inject , @Value ,...

I tried to change user as:

@Named
@Scope(value="session")
public class User { ...
    @Inject
    private AccountServices accountServices;

}

and inject the User in instead of calling new User, but I get the error:

Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
    at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)

Well although it describes the error, but I can not find how can I fix it, and I am not sure if this is the correct way at all. It seems that I can only use spring session scope been when I am using spring mvc

Any comments ?!


Why I need this ?! (Simplified situation)

The user object has a getAccounts() methods which get all user accounts. Getting user accounts is an expensive operation, and it is possible that a user does not require its accounts during its login.

So, instead of get user accounts as soon as user logs in, we let the get method get user accounts if it does not have it:

public class User() {
  private Accounts accounts;

  @Inject
  private AccountServices accountServices;

  Accounts getAccounts() {
    if (accounts == null) {
      accounts = accountServices.getUserAccountsFromDB(...)
    }
    return accounts;
  }

Upvotes: 3

Views: 987

Answers (1)

Aleksandr M
Aleksandr M

Reputation: 24406

Don't create a new instance of User by yourself, instead get a bean from Spring context.

For example you can achieve it by implementing ApplicationContextAware interface and calling one of getBean methods.

User user = applicationContext.getBean(User.class);
// populate user and put it into session

In that way it is a Spring managed bean an all required properties should be injected.

BUT consider changing your User to a simple POJO and moving all business logic (such as fetching users accounts) to some more appropriate place, in that way your model layer will be cleaner and easily testable.

Upvotes: 3

Related Questions