0

In a JSF 2 application, which is developed on tomcat, I have the following SessionScoped managed bean:

@ManagedBean(name = "loginBean")
@SessionScoped
public class LoginBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private String login;
    private String password;

    @ManagedProperty(value = "#{authenticationService}")
    transient private AuthenticationService authenticationService;

    public String login() {

        boolean success = authenticationService.login(login, password); // after restarting tomcat, authenticationService is null here!

        //........
    }
}

authenticationService is a spring's @Service:

@Service("authenticationService")
public class AuthenticationServiceImpl implements AuthenticationService, Serializable {

    private static final long serialVersionUID = 1L;

    //....
}

Also, I've defined the session to be saved on the client side:

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

THE PROBLEM:

the LoginBean works fine when I start tomcat first time in the morning. But if I then restart tomcat and immediately try to access LoginBean.login(), I am getting a NullPointerException on authenticationService.

I have defined authenticationService to be transient so that it won't be saved to the session. But when restarting tomcat, it is not injected again with the refrence to the spring bean authenticationService.

Questions:

  1. Why is it not re-injected during start up?
  2. Why did defining authenticationService as transient not signal JSF to re-inject authenticationService?
  3. Is the problem affected by setting javax.faces.STATE_SAVING_METHOD as client?
  4. How can I solve this problem? If your solution is affected by the value of javax.faces.STATE_SAVING_METHOD, please explain how.
rapt
  • 11,810
  • 35
  • 103
  • 145
  • I have no idea as to the Spring part since I've never really used it, but I just wanted to let you know that this problem doesn't occur when using EJBs (which is what Spring is trying to supplant). You should only not make the service property `transient`, because you're then basically telling that it should never be serialized. – BalusC Mar 25 '12 at 04:09
  • If you use Spring, it is always better to use Spring IoC container than JSF container for injection. This way you can even manage code easily. Follow this [question's](http://stackoverflow.com/questions/8925170/jsf-2-inject-spring-bean-service-with-managedproperty-and-no-xml/8933642#8933642) answer on how to integrate JSF with Spring – Ravi Kadaboina Mar 25 '12 at 06:52
  • @BalusC Thanks! if I don't set the service property as `transient`, it will be deserialized after restarting server, but all its internal data will be stale, plus it won't be attached to the Spring `applicationContect'. What I want for the service bean is to be recreated and autowired **by Spring** during restart, just like Spring does when tomcat finds no serialized session that was saved to the disk before restart but the user tries to access the server with the same session id (same cookie) AFTER restart. Please see http://stackoverflow.com/questions/3778353 – rapt Mar 25 '12 at 23:37
  • @Ravi I think my code should have worked the way it is. Please take a look at this sample project: http://technology-for-human.blogspot.com/2011/01/jsf-2-with-spring-3-protection-with.html (you can download the code and check it out). This code actually does work for me, on a fresh installation of tomcat 7. The problem is, it does not work on my production tomcat (same version) which underwent some config modifications (not sure which, I haven't made them). It could be that by default tomcat 7 doesn't serialize session. Where else could I change this setting? Please see mrembisz' answer below. – rapt Mar 26 '12 at 00:11

1 Answers1

2

This is most likely due to session serialization done by tomcat. It is trying to restore your serialized session but won't inject authenticationService. You can safely disable this feature, it is seldom of any use. To disable it, look up tomcat's conf/context.xml and uncomment section described as responsible for session persistence management.

mrembisz
  • 12,722
  • 7
  • 36
  • 32
  • I guess that could have been the solution in most cases. But I just checked out `conf/context.xml` and that part is already commented out. But clearly this is caused by an old session being (not so cleverly) restored by tomcat. If I make sure to remove my app cookie (JSESSIONID) before accessing the app again (after restarting tomcat) - autowiring works fine as expected. Are there other places in tomcat where this feature could be enabled that I have overlooked? – rapt Mar 26 '12 at 00:00
  • update: my mistake, your solution does work! For some reason I read that I should comment, instead of uncomment. And I found out that similar code worked on other servers without need to disable the tomcat session serialization, because the SessionScoped bean was not actually Serializable, because of transitive dependency in a non-Serializable member object. So during restart, deserialization failed and the whole managed bean was recreated (correctly, with autowiring). – rapt Mar 26 '12 at 03:18
  • To sum it up, in Tomcat, if you use `@ManagedProperty` to inject `@ManagedBean` or Spring bean to a property of a `@SessionScoped` bean, disable the session persistence in conf/context.xml (since `@ManagedProperty` is not called to re-inject the property during deserialization); or use one of the two solutions here: http://stackoverflow.com/questions/3778353 – rapt Mar 26 '12 at 03:31