4

I have two @ManagedBean (javax.faces.bean.ManagedBean), parent and child. The parent managed bean is not abstract because we have to give liberty to the developer to use the parent if enough or inherit it with a child that holds specifically funcionality.

I have problems with the injections bean and the @PostConstruct annotated method in the parent bean.

The following code is the only way I found it works.

@ManagedBean(name = "myBean")
@SessionScoped
public class BaseBean implements Serializable {
    @ManagedProperty(value = "#{serviceManagerController}")
    protected ServiceManagerController serviceManagerController;

     @PostConstruct
     public void init() {
       //do things
     }
}

And the child bean

public class ChildBean extends BaseBean {
    @PostConstruct
    public void init() {
       super.init();
    }
}

To override the "myBean" bean and force to the app to use the child bean when needed I have had to declare the child bean in faces-config.xml

<managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>package.ChildBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
        <property-name>serviceManagerController</property-name>
        <property-class>package.ServiceManagerController</property-class>
        <value>#{serviceManagerController}</value>
    </managed-property>
</managed-bean>

That is the only way all works and I don´t understand some things.

  1. If I don´t declare the child bean in faces-config.xml then the beans container always uses the parent bean implementation though @ManagedBean is inherited.
  2. The injections in parent bean, like serviceManagerController are not performed unless I declare the <managed-property> in the faces-config.xml child bean declaration.
  3. The @PostConstruct method is not executed in the parent child, just the @PostConstruct child. Because of that I have to call super.init() in an empty @PostConstruct mehtod in the child bean

Why do I have to do this three steps to make injections and postConstruct in the parent work?

Of course, if in my app I don´t want to inherit BaseBean and want to use this bean in the facelets all work without problems.

Regards

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
althor
  • 739
  • 2
  • 9
  • 21
  • If you have some commonality to share across different managed beans (common functionality), then wrap it around an abstract class (not a managed bean) and make that abstract class to be inherited by any managed bean of your interest avoiding overusing inheritance. – Tiny Jun 13 '15 at 18:46
  • JSF doesn't [handle inheritance of annotations](http://stackoverflow.com/questions/6661499/jsf-2-managedbean-not-detected) the way you'd [expect](http://stackoverflow.com/questions/6627384/jsf-2-is-it-possible-to-inherit-managedbean). Restructure your parent bean accordingly – kolossus Jun 13 '15 at 22:16
  • See also my answer here: https://stackoverflow.com/a/46792693/1599699 – Andrew Oct 17 '17 at 14:33

1 Answers1

4

The BaseBean is wrongly designed. Bean management annotations are not inherited. It does technically not make any sense to have multiple instances of different subclasses registered on the very same managed bean name/identifier. The BaseBean class must be abstract and not have any bean management annotations (so that neither you nor JSF can "accidentally" instantiate it). Put those bean management on ChildBean instead. Your faces-config.xml "fix" does basically exactly that.

public abstract class BaseBean implements Serializable {

    @ManagedProperty("#{serviceManagerController}")
    protected ServiceManagerController serviceManagerController;

    @PostConstruct
    public void init() {
        // ...
    }

    // ...
}
@ManagedBean("myBean")
@SessionScoped
public class ChildBean extends BaseBean {
    // ...
}

Managed property and post construct / pre destroy annotations are however inherited, provided that you didn't already override them in the subclass. So you don't need to redefine them.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I didn´t override managed properties in the subclass because the hierarchy but I have to declare them in the faces-config.xml. If I don´t do this then the injections of the managed properties (declared in the parent class) are not performed. I don´t understand why it is needed to add them to faces-config – althor Jun 14 '15 at 08:48
  • When you (re)define a backing bean class as managed bean in `faces-config.xml`, all annotations on that class are ignored. Just don't define managed beans in `faces-config.xml` at all. Remove all `` entries. That's the old JSF 1.x way of registering managed beans. – BalusC Jun 14 '15 at 08:51
  • The point is I declare the BaseBean as managedbean because this class is defined in my framework and holds a lot of functionality and the majority of apps that we implement use this basebean in the facelets, without inherit it. But other apps need to override some method, then this apps need to inherit and use the child implementation. In the second case the only way I found that the jsf container instance the child implementation instead the parent one is to delcare child in faces-configxm. To annotated the child with managedname and the same name that parent does not work – althor Jun 14 '15 at 09:14