在CompositeComponent JSF上获取cc.attrs和ValueExpression的列表

时间:2014-03-06 16:19:12

标签: el composite-component jsf-2.2

我应该创建一个复合组件并将其插入父组件中。我试着在stackOverflow上找到我的问题的答案,我发现了这个:

Add programmatically composite component in backing bean

所以,我创建了复合组件:

    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://xmlns.jcp.org/jsf/passthrough"
    xmlns:composite="http://java.sun.com/jsf/composite"
    xmlns:ic="http://java.sun.com/jsf/composite/inputComponent">

<composite:interface>
    <composite:attribute name="idPanel" required="true" />
    <composite:attribute name="typeBSPanel" default="default" />
    <composite:attribute name="idPanelHeading" required="true" />
    <composite:attribute name="idPanelBody" required="true" />
    <composite:attribute name="listInputText" required="true"
        shortDescription="Questo componente è un Panel con un numero variabile di InputText di tipo Text, Number e DropDown. Questa lista deve contenere degli oggetti con le seguenti proprietà: label, value e placeholder."></composite:attribute>
    <composite:attribute name="objectBindToPanel" required="true" />
</composite:interface>

<composite:implementation>
    <div class="panel-group" id="accordion">
        <div id="#{cc.attrs.idPanel}"
            class="panel panel-#{cc.attrs.typeBSPanel}">
            <div id="#{cc.attrs.idPanelHeading}" class="panel-heading">
                <button type="button" class="btn btn-#{cc.attrs.typeBSPanel}"
                    data-toggle="collapse" data-target="#collapseBodyPanel">
                    +/-</button>
            </div>
            <div id="collapseBodyPanel" class="panel-collapse collapse in">
                <div id="#{cc.attrs.idPanelBody}" class="panel-body">
                    <ui:repeat var="inputText" value="#{cc.attrs.listInputText}">
                        <ic:inputTextBS preAddon="#{inputText.label}"
                            requiredMessage="This field must not be empty"
                            placeholder="#{inputText.placeholder}"
                            value="#{cc.attrs.objectBindToPanel[inputText.value]}" required="true">
                        </ic:inputTextBS>
                    </ui:repeat>
                </div>
            </div>
        </div>
    </div>
</composite:implementation>

</html>

用于以动态方式添加复合组件的类和方法:

    public class CCUtility {

    public static void includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id, Map<String, String> mapValueExpression) {
        // Prepare.
        FacesContext context = FacesContext.getCurrentInstance();
        Application application = context.getApplication();
        FaceletContext faceletContext = (FaceletContext) context.getAttributes().get("javax.faces.FACELET_CONTEXT");

        // This basically creates <ui:component> based on <composite:interface>.
        Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);
        UIComponent composite = application.createComponent(context, resource);
        composite.setId(id); // Mandatory for the case composite is part of UIForm! Otherwise JSF can't find inputs.

        ExpressionFactory factory = application.getExpressionFactory(); 
        ELContext ctx = context.getELContext(); 
        for (Map.Entry<String, String> entry : mapValueExpression.entrySet()) { 
            ValueExpression expr = factory.createValueExpression(ctx, entry.getValue(), String.class); 
            composite.setValueExpression(entry.getKey(), expr); 
            //composite.getAttributes().put(entry.getKey(), entry.getValue());
            }

        // This basically creates <composite:implementation>.
        UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE);
        implementation.setRendererType("javax.faces.Group");
        composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation);

        // Now include the composite component file in the given parent.
        parent.getChildren().add(composite);
        parent.pushComponentToEL(context, composite); // This makes #{cc} available.
        try {
            faceletContext.includeFacelet(implementation, resource.getURL());
        } catch (IOException e) {
            throw new FacesException(e);
        }
    }


}

我在另一个类中调用前一个方法,该类传递复合组件所需的属性映射:

public void addPanelHostMachine(){
    this.dataCenterController.getDataCenter().getGroupsHost().add(indexGroupHostMachine, new GroupHost());
    Map<String, String> mapValueExpression = new HashMap<String, String>();
    mapValueExpression.put("idPanel", "panelHostMachine" + indexGroupHostMachine);
    mapValueExpression.put("idPanelHeading", "panelHostMachineHeading" + indexGroupHostMachine);
    mapValueExpression.put("idPanelBody", "panelHostMachineBody" + indexGroupHostMachine);
    mapValueExpression.put("typeBSPanel", "success");
    mapValueExpression.put("listInputText", "#{dataCenterController.dataCenter.groupsHost.get(" + indexGroupHostMachine + ").listOfInputText}");
    mapValueExpression.put("objectbindToPanel", "#{dataCenterController.dataCenter.groupsHost.get(" + indexGroupHostMachine + ")}");
    CCUtility.includeCompositeComponent(panelBodyDataCenter, "panelComponent", "panelComponent.xhtml", "ccPanelHostMachine" + indexGroupHostMachine, mapValueExpression);
    indexGroupHostMachine = indexGroupHostMachine + 1;
}

现在的问题是,当我尝试添加CompositeComponent时,我收到此错误:

Grave: Servlet.service() for servlet [Faces Servlet] in context with path [/IcaroKBMassiveEditor] threw exception [/resources/panelComponent/panelComponent.xhtml @34,79 preAddon="#{inputText.label}": Property 'label' not found on type java.lang.String] with root cause
javax.el.PropertyNotFoundException: Property 'label' not found on type java.lang.String

我认为这是EL表达式和'composite:attribute'的问题,但我不知道如何解决这个问题。任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:2)

我在这篇文章中找到了解决方案:DataTable Inside Composite Component

而不是:

for (Map.Entry<String, String> entry : mapValueExpression.entrySet()) { 
 ValueExpression expr = factory.createValueExpression(ctx, entry.getValue(),String.class); 
  composite.setValueExpression(entry.getKey(), expr); 
        }

我用过:

for (Map.Entry<String, String> entry : mapValueExpression.entrySet()) { 
 ValueExpression expr = factory.createValueExpression(ctx, entry.getValue(),Object.class); 
  composite.setValueExpression(entry.getKey(), expr); 
        }

我在funciton call String.Class中将Object.class替换为factory.createValueExpression