如何扩展com.sun.jsf.mgbean.ManagedBeanBuilder

时间:2012-10-09 13:53:00

标签: java jsf jsf-2 managed-bean

我想扩展 com.sun.jsf.mgbean.ManagedBeanBuilder 。我在哪里注册这样的课程?

原因是,我需要在PostConstruct之前的bean-to-create中设置一个值(基于正在创建的bean)。所以我不得不改变 com.sun.faces.mgbean.BeanBuilder.build 方法:

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;
}

..之后在 MyManagedBeanELResolver 的revoleBean(在faces-config.xml中注册为el-resolver)方法:

result = manager.create(beanName, builder, facesContext);
if (result instanceof SomeInterface) {
  ((SomeInterface) result).setValue(...)
  builder.invoktePostConstruct(result);
}

有更好的解决方案吗?

更新为什么我不能使用kolossus提出的PhaseListener
我不能使用viewId来获取ManagedBean,因为我希望当前有活动的 n 类型的Bean,每个都可以通过它们的bean名称访问。

我在viewId和ManagedBean之间有一个1:n的关系,例如我有一个 test.jsf ,它有一个支持bean TestBean 。也可能存在一个 TestBean0 ,它就是一个 TestBean 的副本,但是具有不同的值(我需要注入,例如“userId”) 。我的 test.jsf (连同 ControllerBean 能够确定应该访问哪个ManagedBean, TestBean TestBean0 ,显示来自 TestBean 的内容(例如userId = 27)或* TestBean_0 *(例如userId = 33)。
这允许我在 n 模型( TestBean )中显示 1 视图( test.jsf )同一页面,例如我的test.html看起来像这样。

....
<h:outputText value="#{controllerBean.getBean('testBean', component).name}" />
<f:subview id="someId">
  <ui:include src="/WEB-INF/templates/test.xhtml" />
</f:subview>
....

因此,我可以进行递归(在这种情况下,递归的深度为1),其中0级的outputText显示名称“Your userId is 27”,包含的test.xhtml的outputText显示“Your userId is 33" 。

1 个答案:

答案 0 :(得分:0)

我的解决方案如下(不完全是我想要的,但直到现在我还没有找到更好的方法):

由于我无法扩展 ManagedBeanBuilder ,我决定创建自己的BeanManager( MyBeanManager )。它的行为与 com.sun.faces.mgbean.BeanManager getBeanFromScope create 方法相同,但在上略有不同getBuilder

if (getRegisteredBeans() != null) {
  BeanBuilder builder = getRegisteredBeans().get(name);
  if (builder instanceof ManagedBeanBuilder) {
    builder = new MyManagedBeanBuilder(builder.getManagedBeanInfo());
  }
  return builder;
}
return null;

所以我能够注入 MyManagedBeanBuilder 并使用我上面提出的构造:

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;
}

..并且为了在我将所需的值设置到bean之后调用 @PostConstruct ,我必须覆盖 invokePostConstruct 以使其 public < / em>而不是 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);
  }
}

..最后在 MyManagedBeanELResolver 我能够将所需的值设置到bean中,而不需要先调用 @PostConstruct 。在 MyManagedBeanELResolver

if (result instanceof SomeInterface) {
  ((SomeInterface) result).setValue(value);
  ((MyManagedBeanBuilder) builder).invokePostConstruct(result, getInjectionProvider());
}