从复合组件获取 bean class

Get bean class from composite component

我有复合组件:

<my:component value="#{bean.property1.property2}/>

从复合组件中,我需要获取 class of bean.property1 才能读取其注释。 我通过以下代码完成:

ValueExpression valueExpression = expressionFactory.createValueExpression(FacesContext.getCurrentInstance().getELContext(),
                        "#{bean.property1}", Object.class);
Object bean = valueExpression.getValue(FacesContext.getCurrentInstance().getELContext());
Class<?> beanClass = bean.getClass();

这很好用,但是如果我从 facelet 使用 my:component 并通过 ui:param 作为参数传递 bean 这不起作用,因为 bean 不能已解决。

可能我应该使用 FaceletContext 作为 ELContext 而不是 FacesContext.getCurrentInstance().getELContext():

FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes()
                    .get("javax.faces.FACELET_CONTEXT");

但这不适用于 RENDER_RESPONSE 阶段(来自 encodeBegin 方法)。它 returns 最后使用 ELContext 而不是实际上下文(我并不感到惊讶 :))。

目标是从 my:component 中获得 #{bean.property1} 中的 class。我该怎么做?

这很容易 RichFaces:

    ValueExpressionAnalayser analyser = new ValueExpressionAnalayserImpl();
    ValueDescriptor valueDescriptor = analyser.getPropertyDescriptor(context, valueExpression);
    Class<?> beanClass = valueDescriptor.getBeanType();

这对我来说没问题。

javax.faces.validator 包中也有 ValueExpressionAnalayzer,但它是包私有的,不能使用。

您可以将 bean 作为参数传递给组件。

1) 在组件接口文件中声明属性(如果使用复合组件):

<cc:interface componentType="myComponentClass">
    <cc:attribute name="myBean" preferred="true"/>
    ..others attributes
<cc:interface>

2) 在组件 class(myComponentClass)

中为 "myBean" 属性实现各自的 getter 和 setter
protected enum PropertyKeys {
    myBean;

    String toString;

    PropertyKeys(String toString) {
        this.toString = toString;
    }

    PropertyKeys() {}

    @Override
    public String toString() {
        return ((this.toString != null) ? this.toString : super.toString());
    }
}
public YourBeanClass getMyBean() {
    return (YourBeanClass) getStateHelper().eval(PropertyKeys.myBean,   null);
}
public void setMyBean(YourBeanClass myBean) {
    getStateHelper().put(PropertyKeys.myBean, myBean);
}

3) 在你的 jsf 页面上设置属性:

<my:component myBean="#{bean}"/>

4) 在组件的渲染中 class 将 UIComponent 转换为 myComponentClass。

@Override
public void encodeBegin(FacesContext pContext, UIComponent pComponent)
    throws IOException {
    myComponentClass myComponent = (myComponentClass) pComponent;
    myComponent.getYourAttribute();
}