6
\$\begingroup\$

Im trying to solve two problems I see with JSF2 and Spring.

First

  • @Autowired in @ManagedBean does not work
  • Nor does @ViewScoped with @Controller
  • @ManagedProperty is not type safe and requires setter

Second

  • You can not serialize singleton spring beans without hassle
  • Managed beans must be serializable so the container can serialize the session

So I enabled @Autowired in managed beans and fixed serialization with this common base class which all managed beans (at least @SessionScoped and @ViewScoped ones) derive from.

public abstract class Handler implements Serializable {
    private static final long serialVersionUID = 1L;

    @PostConstruct
    private void init() {
        Spring.appCtx.getAutowireCapableBeanFactory().autowireBean(this);
    }

    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        Spring.appCtx.getAutowireCapableBeanFactory().autowireBean(this);
    }
}

Handlers are now implemented like that:

@ManagedBean
@RequestScoped
public class Index extends Handler implements Serializable {
    private static final long serialVersionUID = 1L;

    @Autowired
    SampleService ss;

    public String hello() {
        return ss.sayHello();
    }
}

First tests seem fine, but I'm curious if I'm causing any problems I don't know of.

\$\endgroup\$
  • 1
    \$\begingroup\$ You might consider making the service reference transient. transient SampleService ss; \$\endgroup\$ – cjstehno Mar 25 '13 at 12:40
  • \$\begingroup\$ @cjstehno: Could you write your comment as an asnwer to help us killing a zombie? meta.codereview.stackexchange.com/a/1511/7076 \$\endgroup\$ – palacsint Feb 26 '14 at 19:35
  • 1
    \$\begingroup\$ Sure. No problem. Done. \$\endgroup\$ – cjstehno Feb 26 '14 at 20:18
  • \$\begingroup\$ You can make your Managed bean Extends 'SpringBeanAutowiringSupport' \$\endgroup\$ – Daouda Beye Jan 8 '17 at 18:12
6
\$\begingroup\$
  1. Handler is too generic name for a class. Try to find something more descriptive (which doesn't force readers to check the implementation if they want to know what the class does), SerializationHandler, for example.

  2. In Java classes could have only one superclass. If you make it an abstract superclass you can't have another one which might be cumbersome in some cases.

    Inheritance is appropriate only in circumstances where the subclass really is a subtype of the superclass. In other words, a class B should extend a class A only if an “is-a” relationship exists between the two classes. If you are tempted to have a class B extend a class A, ask yourself the question: Is every B really an A? If you cannot truthfully answer yes to this question, B should not extend A. If the answer is no, it is often the case that B should contain a private instance of A and expose a smaller and simpler API: A is not an essential part of B, merely a detail of its implementation.

    Source: Effective Java, Second Edition, Item 16: Favor composition over inheritance

    I'd use composition with a helper class:

    @ManagedBean
    @RequestScoped
    public class Index implements Serializable {
        private static final long serialVersionUID = 1L;
    
        @Autowired
        SampleService ss;
    
        public String hello() {
            return ss.sayHello();
        }
    
        @PostConstruct
        private void init() {
            WireHelper.wireObject(this);
        }
    
        private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
            ois.defaultReadObject();
            WireHelper.wireObject(this);
        }
    }
    
    public final class WireHelper {
        public static void wireObject(Object object) {
            Spring.appCtx.getAutowireCapableBeanFactory().autowireBean(this);
        }
    }
    
  3. If you stay with the original implementation: you don't necessarily need implements Serializable here since Handler already implements that interface:

    public class Index extends Handler implements Serializable {
        ...
    }
    
\$\endgroup\$
  • \$\begingroup\$ 1) Good idea but does not matter too much because every ManagedBean will implement Handler. 2) I don't know if you are familiar with jsf, but there will be multiple ManagedBeans (some call them handlers) per jsf page, which may get easily into hundreds in a big app. If you don't extend, you will have to reimplement readObject() every time. Too much duplication and very error prone (may be forgotten, hard to check). The solution we chose one year ago was simply to turn of session serialization in tomcat. Using @Scopes proxyMode works, too). \$\endgroup\$ – atamanroman Feb 26 '14 at 21:25
  • \$\begingroup\$ @atamanroman: Thanks for the feedback! Just to make sure: "turn of" -> "turn off" - is it a typo? \$\endgroup\$ – palacsint Feb 26 '14 at 21:32
  • 1
    \$\begingroup\$ Yes of course, sorry. Can't edit anymore, though. \$\endgroup\$ – atamanroman Feb 26 '14 at 22:10
  • \$\begingroup\$ With Java 8 you can use default methods to achieve both! Interface without Code duplication :-) \$\endgroup\$ – Falco May 15 '15 at 7:57
3
\$\begingroup\$

You might consider making the service reference transient.

transient SampleService ss;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.