【问题标题】:Using dynamic ui:include inside ui:repeat results in NullPointerException在 ui:repeat 中使用动态 ui:include 会导致 NullPointerException
【发布时间】:2012-03-07 14:25:12
【问题描述】:

我想通过使用<ui:repeat> 和<p:dialog> 和<ui:include> 创建动态对话窗口。但是当我尝试如下时有一个例外。

main.xhtml

<p:outputPanel id="windowsPanel" layout="block" style="width:100%;">
    <p:outputPanel rendered="#{mainView.dynamicWindows ne null}">
        <ui:repeat var="item"  value="#{mainView.dynamicWindows}">
            <p:dialog binding="#{item.dialog}">
                <ui:include src="#{item.includedWindowPath}" />
            </p:dialog>
        </ui:repeat>
    </p:outputPanel>
</p:outputPanel>

MainView.java

@ManagedBean(name = "mainView")
@SessionScoped
public class MainView extends BaseView {

private static final long serialVersionUID = -6291834350102049312L;

private List<Window> dynamicWindows;

@PostConstruct
public void init() {
    fillWindows();
}

private void fillWindows() {
    dynamicWindows = new ArrayList<Window>();

    for (int i = 0; i < 3; i++) {
        Window window = new Window("Header " + i);
        window.getDialog().setId("_dynamicWindow" + i);
        window.getDialog().setWidgetVar("_dynamicWindowWidget" + i);
        dynamicWindows.add(window);
    }
}

// getters & setters

例外:

javax.servlet.ServletException: /main.xhtml @33,42 binding="#{item.dialog}": Target Unreachable, identifier 'item' resolved to null
    javax.faces.webapp.FacesServlet.service(FacesServlet.java:422)
    org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:369)
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:168)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

【问题讨论】:

    标签: jsf facelets uirepeat uiinclude


    【解决方案1】:

    &lt;ui:include&gt; 是在视图构建期间运行的标签处理程序,而&lt;ui:repeat&gt; 是在视图渲染期间运行的 UI 组件。标记处理程序生成 JSF UI 组件树。 JSF UI 组件生成 HTML。它们不同步运行。

    因此,当&lt;ui:include&gt; 运行时,&lt;ui:repeat var&gt; 指定的#{item} 在范围内根本不可用,因为当时&lt;ui:repeat&gt; 尚未运行。您需要一个迭代标记处理程序而不是一个迭代 JSF UI 组件。 JSTL &lt;c:forEach&gt; 就是这样一个。将 &lt;ui:repeat&gt; 替换为 &lt;c:forEach&gt; 应该可以解决此问题。然而,它可能有不良副作用。由于您的具体功能要求并不完全清楚,因此很难事先判断。

    另见:

    【讨论】:

    • 感谢您的回答。但是当我尝试使用 c:forEach 时,同样的异常再次出现在 p:dialog 行。我想生成动态对话框窗口,这些对话框的内容应该是可替换的。所以我使用了 ui:include。也许我使用的方式不是正确的方式。对话的数量并不重要。可能有零个或 n 个对话框。将只有一页。并且用户单击任何链接我将生成窗口对象并使用生成的对话框重新呈现页面。如果用户点击学生链接,对话框的内容将为students.xhtml。
    • @BalusC:我也有类似的要求,即使用 ui:repeat 构建项目列表,但使用 ui:include 为列表中的每个项目使用动态选择的模板。我已经经历过这个和类似的其他问题,但我意识到即使 c:forEach 也不是一个很好的解决方案,因为它会导致巨大的组件树(如果包含的模板很复杂),因此性能不佳,另一方面使用 ui:repeat 只会构建一个较小的组件树。此外,由于其他一些原因,我也被限制使用 c:forEach,那么处理这个问题的正确方法(不仅仅是一种解决方法)是什么?
    • 我们需要一个新的自定义组件吗?
    • Isn't using multiple ui:fragment(s)(within ui:repeat) with rendered 属性在创建组件树方面更好的解决方案不会像@的情况那样太大987654334@? (ok, that would be acceptable only when the no of cases for chosing templates is bearably small & less than no of items in list)\.
    • @user01:这不是真的。 rendered 属性在视图渲染期间进行评估。是的,&lt;ui:fragment&gt; 是 UIComponent。
    【解决方案2】:

    如果您说要在 ui:repeat 中动态选择和包含一个项目,那么可能值得这样做,因为如果要迭代的列表更大,它将使您免于使用 c:forEach 构建巨大的组件树。这将有条件地仅呈现几种情况中的一种以包含 xhtml。这些情况不会在组件树中重复多次,每次在您的列表中。希望这应该提供更好的性能,并且还可以避免将 JSF 与 JSTL 混合的担忧。

        <ui:repeat var="item"  value="#{mainView.dynamicWindows}">
             <h:panelGroup rendered="#{booleancase1}">
                <ui:include src="case1.xhtml" />
             </h:panelGroup>
    
             <h:panelGroup rendered="#{booleancase2}">
                <ui:include src="case2.xhtml" />
             </h:panelGroup>
    
             <h:panelGroup rendered="#{booleancase3}">
                <ui:include src="case3.xhtml" />
             </h:panelGroup>
    
             <h:panelGroup rendered="#{booleancase4}">
                <ui:include src="case4.xhtml" />
             </h:panelGroup>
        </ui:repeat>
    

    【讨论】:

    • 您的介绍不正确。 &lt;h:panelGroup&gt; 根本不会在视图构建期间运行,因此您仍然会得到相同大小的组件树。只有 HTML 输出大小会减小。如果您真的想减小组件树的大小,请改用&lt;c:if&gt; 或&lt;c:choose&gt; ——当然,这又需要&lt;c:forEach&gt; :)
    • 正如我在之前的 cmets 中所说,c:forEach 循环内的组件在组件树中重复的次数与列表大小一样多(不是这样吗?真的!?),但是使用 ui:repeat 不应该是这种情况,不!? ui:repeat 只在组件树中包含其中的组件一次..?!
    • JSTL 在视图构建期间运行,而不是在视图渲染期间运行。您的代码会生成一个组件树,其内容为 all 包含文件,这些文件仅在视图渲染期间有条件地渲染。如果您使用了&lt;c:forEeach&gt; 和&lt;c:choose&gt;,那么代码将生成一个组件树,其内容为only 始终呈现的所需包含文件。仔细阅读stackoverflow.com/questions/3342984/… 以更好地理解“视图构建时间”与“视图渲染时间”。
    • 我已经浏览了你链接的帖子,也理解并同意你所说的,但我只是想强调一下c:forEach是否重复循环内的组件对于列表中的每一个项目 vs ui:repeat 只包含其中的组件一次(是的,我非常理解所有包含的组件/文件都将被包含,并且在渲染期间渲染一个,但包含只是一次而不是重复c:forEach 的情况)。我希望你能理解我想要表达的意思。
    • &lt;ui:include&gt; 也在视图构建期间运行。您当前的代码仍然以最终 JSF 组件树中的 ALL 包含文件的内容结束(稍后在视图呈现时间有条件地呈现)。当使用&lt;c:if&gt; 或&lt;c:choose&gt; 有条件地将&lt;ui:include&gt; 添加到JSF 组件树而不是使用rendered 属性有条件地呈现HTML 输出时,不会发生这种情况。
    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    相关资源
    最近更新 更多