使用可选的 facelet 标签库

Using optional facelet tag libraries

我有一个使用可选模块的 Web 应用程序。这些模块作为 Web 片段项目实现,它们的 jar 可能会或可能不会部署 war 取决于构建配置文件。

一个模块可以包含它自己的 module.taglib.xml,带有 http://company.com/module 命名空间和一些标签。

war xhtml 模板使用如下模块标签:

<ui:composition ... xmlns:mod="http://company.com/module">

<c:if test="#{moduleDeployed}">
    <mod:someTag />
</c:if>

问题。

  1. 当模块未部署时,war 页面工作正常,但在 ProjectStage.Development 中我收到 FacesMessage warnings:

    Warning: This page calls for XML namespace http://company.com/module declared with prefix mod but no taglibrary exists for that namespace.

  2. 据我所知,JSF 规范没有定义当模板使用不存在的标签库时会发生什么。因此,使用我当前的方法 war 页面可以在升级或切换到不同的 JSF 实现后停止工作。

问题。

  1. 有没有(不是很丑陋的)方法来禁用这个特定的 warning?
  2. 是否有更好的方法来使用可选的 facelet 标记库?

截至目前,我计划尽我所能禁用 warning:例如覆盖消息渲染器并在必要时检查消息字符串。如果出现问题 2,请为未部署的模块创建构建供应占位符 taglib.xml 文件。

尽管占位符标签库似乎是一个很好的解决方案,但它们似乎也更难实施和维护。

所以最后我过滤了消息。这可能是 Mojarra 特有的:消息文本,迭代器允许删除的事实(规范不禁止,但也不是必需的)。它可以与 Mojarra 2.2.8 到 2.2.13 一起使用。

public class SuppressNoTaglibraryExistsFacesMessage implements SystemEventListener {
    private static final Pattern PTTRN_NO_TAGLIBRARY_EXISTS_FOR_NAMESPACE =
            Pattern.compile("Warning: This page calls for XML namespace \S+ declared with "
            + "prefix \S+ but no taglibrary exists for that namespace.");

    @Override
    public void processEvent(SystemEvent event) {
        Iterator<FacesMessage> messages = FacesContext.getCurrentInstance().getMessages();
        while (messages.hasNext()) {
            String messageSummary = messages.next().getSummary();
            if (PTTRN_NO_TAGLIBRARY_EXISTS_FOR_NAMESPACE.matcher(messageSummary).matches()) {
                messages.remove();
            }
        }
    }

    @Override
    public boolean isListenerForSource(Object source) {
        return true;
    }
}

仅在开发项目阶段绑定侦听器。

public class SubscribeListenersAfterApplicationPostConstructListener
        implements SystemEventListener {
    @Override
    public void processEvent(SystemEvent event) throws AbortProcessingException {
        Application application = (Application) event.getSource();
        if (ProjectStage.Development.equals(application.getProjectStage())) {
            application.subscribeToEvent(PostAddToViewEvent.class, UIViewRoot.class,
                    new SuppressNoTaglibraryExistsFacesMessage());
        }
    }

    @Override
    public boolean isListenerForSource(Object source) {
        return source instanceof Application;
    }

}

在脸上-config.xml:

<system-event-listener>
    <system-event-listener-class><packages>.SubscribeListenersAfterApplicationPostConstructListener</system-event-listener-class>
    <system-event-class>javax.faces.event.PostConstructApplicationEvent</system-event-class>
</system-event-listener>