Jsf 如何扩展UISelectOne组件for enum属性以自动将所有枚举值填充为选择项?

Jsf 如何扩展UISelectOne组件for enum属性以自动将所有枚举值填充为选择项?,jsf,jsf-2,selectonemenu,custom-tag,Jsf,Jsf 2,Selectonemenu,Custom Tag,我想使用简化的selectone标记,它会自动为枚举生成selectitems列表。因此,结果将是: <s:enumSelectOneMenu value="#{myBean.enumValue}"/> 因此,在组件内部,我可以使用反射获取枚举类型和所有枚举值。因此,基本上我需要覆盖来自UiSelectOne的唯一一个方法validateValue(..),并将UiSelectItems列表作为子项放在那里(与Tomahawk中的方法相同,请参见SelectOneLanguag

我想使用简化的selectone标记,它会自动为枚举生成selectitems列表。因此,结果将是:

<s:enumSelectOneMenu value="#{myBean.enumValue}"/>

因此,在组件内部,我可以使用反射获取枚举类型和所有枚举值。因此,基本上我需要覆盖来自UiSelectOne的唯一一个方法validateValue(..),并将UiSelectItems列表作为子项放在那里(与Tomahawk中的方法相同,请参见SelectOneLanguage组件)

但还应该做些什么呢?我需要在我自己的taglib.xml中描述标记属性,但是jsf-impl.jar不包含FaceletsXML-only标记库文件,所以我不能简单地从那里复制所有内容。另外,如果我在taglib.xml中静态地描述标记,我将不得不在每个新版本的JSF上手动更新它,这一点都不好。那么,在JSF中扩展组件并避免大量手动复制粘贴工作的最佳方法是什么

另外,我使用的是JSF2.0,但复合facelets方式不适合我,因为它会产生很多问题,因为复合元素是由NamingContainer组件包装的。所以我只需要“老派”的方式来创建自定义组件

谢谢。

扩展一些JSF组件并在不丢失属性的情况下添加行为的最佳(但不是最简单)方法之一是使用PrimeFaces JSF插件。有关它的一些信息,请参见:。虽然它有一些硬编码的值(facelets taglib的名称和输出目录的方式,生成的taglib放在哪里),并且可以在本地更改和重建 这里是pfjsf插件的示例

   <!-- Primefaces maven plugin -->
            <plugin>
                <groupId>org.primefaces</groupId>
                <artifactId>maven-jsf-plugin</artifactId>
                <version>1.2.1-SNAPSHOT</version>
                <executions>
                    <execution>
                        <id>generate-ui</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <uri>http://www.mycompany.com/tags</uri>
                            <name>rstk-tag</name>
                            <jsfVersion>2</jsfVersion>
                            <templatesDir>src/main/java-templates</templatesDir>
                            <componentConfigsDir>src/main/resources-maven-jsf/ui</componentConfigsDir>
                            <!-- <standardFacesConfig>src/main/resources-maven-jsf/standard-faces-config.xml</standardFacesConfig> -->
<!-- These are new attributes added manually to plugin source code! -->
                            <standardFaceletsTaglib>src/main/resources-maven-jsf/standard-facelets-taglib.xml</standardFaceletsTaglib>
                            <faceletsOutputDirectory>target/generated-sources/maven-jsf-plugin/META-INF</faceletsOutputDirectory>
                        </configuration>
                        <goals>
                            <goal>generate-components</goal>
                            <goal>generate-facelets-taglib</goal>
                        </goals>
                    </execution>                    
                </executions>
            </plugin>
然后,该组件可以用作简单的JSF选择一个组件(具有所有标准属性),但不要求每次添加选择项,并允许将任何其他子项放置在该组件上:

<s:enumSelectOneMenu value="#{polis.osMatrixType}" id="registryType">
        <p:ajax listener="#{osagoPolisBean.rollOsagoEndDate}" update="osagoUsagePeriod" process="osagoTable" event="change"/>                               
</s:enumSelectOneMenu>  


有什么问题吗?JSF有一个内置的枚举转换器。或者您想避免每次都指定
吗?好的,最好是:
?Upd:正确,我需要避开所有
selectItems
staffI,看看你在说什么。这其实是个好主意。从理论上讲,一个简单的复合组件和一个支持组件应该可以工作,但我宁愿先自己试验一下,看看它是否真的能像我想象的那样工作。如果我有时间,我会发布一个答案,并确认它确实是这样工作的。我与composite的斗争太久了,试图替换那里的p:列(只是以与上面相同的方式扩展)。最后,我又回到了基本的1.2 facelets块,它工作起来很有魅力,因为它不需要任何uinamingContainer,尽管我失去了继承,不得不在我的taglib.xml中复制许多属性。出于上述目的,我可以再次尝试复合元素,但我不希望在我的应用程序中有两个标记库名称空间!很难记住哪个库(自定义库或复合库)包含标记。很抱歉收到了很多信:(

    public class EnumSelectOneMenu extends HtmlSelectOneMenu {
    ... // Generated staff here
    public boolean getRendersChildren() {
            return true;
        }

        /**
         * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext)
         */
        @Override
        public void encodeBegin(FacesContext context) throws IOException {
            super.encodeBegin(context);

            if (context.isPostback()) {
                return;
            }

            UISelectItems selectItems = new UISelectItems();
            try {
                selectItems.setValue(getEnumValuesList());
            } catch (Exception e) {
                log.error("Failed to create enum list", e);
            }
            getChildren().add(selectItems);

        }

        /**
         * Creates the list of select items of format [ENUM, enum.getDisplay()] 
         * @return
         */
        private List getEnumValuesList() {
            List result = new ArrayList();
            ValueExpression ve = getValueExpression("value");
            Class enumClass = ve.getType(getFacesContext().getELContext());
            Method method = ReflectionUtils.findMethod(enumClass, "getDisplay", null);
            for (Object e : ve.getType(getFacesContext().getELContext()).getEnumConstants()) {
                result.add(new SelectItem(e, (String) ReflectionUtils.invokeMethod(method, e)));
            }
            return result;
        }
    }
<s:enumSelectOneMenu value="#{polis.osMatrixType}" id="registryType">
        <p:ajax listener="#{osagoPolisBean.rollOsagoEndDate}" update="osagoUsagePeriod" process="osagoTable" event="change"/>                               
</s:enumSelectOneMenu>