I would like to extend the com.sun.jsf.mgbean.ManagedBeanBuilder. Where do I have to register such a class?
The reason is, I need to set a value (which is based on the bean which is being created) within the bean-to-create before the PostConstruct. So I would have to change the com.sun.faces.mgbean.BeanBuilder.build method:
public Object build(InjectionProvider injectionProvider, FacesContext context) {
Object bean = newBeanInstance();
injectResources(bean, injectionProvider);
buildBean(bean, context);
if (bean instanceof SomeInterface == false) {
invokePostConstruct(bean, injectionProvider);
}
return bean;
}
.. afterwards in MyManagedBeanELResolver's revoleBean (registered in faces-config.xml as el-resolver) method:
result = manager.create(beanName, builder, facesContext);
if (result instanceof SomeInterface) {
((SomeInterface) result).setValue(...)
builder.invoktePostConstruct(result);
}
Is there a better solution to it?
UPDATE why I can't use the PhaseListener proposed by kolossus
I cannot use the viewId to fetch the ManagedBean because I would like to have n types of Bean currently active, each accessed by their bean name.
I have a 1:n relation between viewId and ManagedBean, e.g. I have a test.jsf which has the backing-bean TestBean. It's also possible that a TestBean0 exists which is the, lets say, a copy of TestBean but with a different value (which I need to inject, e.g. a "userId"). My test.jsf (together with a ControllerBean is able to determine which ManagedBean should be accessed, either the TestBean or TestBean0, which shows either the content from the TestBean (e.g. userId=27) or *TestBean_0* (e.g. userId=33).
This allows me to have the 1 view (test.jsf) with n models (TestBean) displayed at in the same page at the same time, e.g my test.html looks like this.
....
<h:outputText value="#{controllerBean.getBean('testBean', component).name}" />
<f:subview id="someId">
<ui:include src="/WEB-INF/templates/test.xhtml" />
</f:subview>
....
So therefore I can have a recursion (depth of the recursion is 1 in this case), where the outputText from the level 0 shows the name "Your userId is 27" and the included test.xhtml's outputText shows "Your userId is 33".
My solution is as follows (not exactly what I wanted, but until now I did not find a better way):
As I wasn't able to extend the ManagedBeanBuilder i decided to create my own BeanManager (MyBeanManager). It behaves equally as the com.sun.faces.mgbean.BeanManager's getBeanFromScope and create method, but a bit differently on getBuilder:
if (getRegisteredBeans() != null) {
BeanBuilder builder = getRegisteredBeans().get(name);
if (builder instanceof ManagedBeanBuilder) {
builder = new MyManagedBeanBuilder(builder.getManagedBeanInfo());
}
return builder;
}
return null;
So i was able to inject MyManagedBeanBuilder and use my construct proposed above:
public Object build(InjectionProvider injectionProvider,
FacesContext context) {
Object bean = newBeanInstance();
injectResources(bean, injectionProvider);
buildBean(bean, context);
if (bean instanceof SomeInterface == false) {
invokePostConstruct(bean, injectionProvider);
}
return bean;
}
.. and in order to invoke @PostConstruct after i set the desired value into the bean, i had to override the invokePostConstruct to make it public instead of protected
public void invokePostConstruct(Object bean, InjectionProvider injectionProvider) {
try {
injectionProvider.invokePostConstruct(bean);
} catch (InjectionProviderException ipe) {
String message = MessageUtils.getExceptionMessageString(
MessageUtils.MANAGED_BEAN_INJECTION_ERROR_ID,
beanInfo.getName());
throw new ManagedBeanCreationException(message, ipe);
}
}
.. finally in MyManagedBeanELResolver I was able to set my desired value into the bean without having @PostConstruct called before. in MyManagedBeanELResolver:
if (result instanceof SomeInterface) {
((SomeInterface) result).setValue(value);
((MyManagedBeanBuilder) builder).invokePostConstruct(result, getInjectionProvider());
}