2012-01-31 1 views
2

ПРИМЕЧАНИЕ: Этот вопрос был сильно отредактирован, так как был найден наработанный пример. Однако проблема остается практически такой же, как и , как представляется, надуманный пример работает.includeViewParams = true не работает в комбинации с композитным компонентом, который выполняет итерацию по коллекции

Рассмотрим следующую JSF страницы:

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> 
    <f:view contentType="text/html"> 
     <h:head> 
      <title>Page</title> 
     </h:head> 
     <h:body> 
      <ui:composition template="/WEB-INF/templates/myLayout.xhtml"> 
       <ui:define name="metadata"> 
        <f:metadata> 
         <f:viewParam name="foobar" value="#{pageBean.foo}"/> 
        </f:metadata> 
       </ui:define> 
       <ui:define name="content"> 
        <h:form> 
         <h:commandLink value="Click" 
            action="#{util.currentPageAction()}"/> 
        </h:form> 
       </ui:define> 
      </ui:composition> 
     </h:body> 
    </f:view> 
</html> 

И эти бобы:

@Named 
@RequestScoped 
public class PageBean implements Serializable 
{ 
    public String getFoo() 
    { 
     return foo; 
    } 

    public void setFoo(String foo) 
    { 
     this.foo = foo; 
    } 

    private String foo; 
} 
@Named 
@ApplicationScoped 
public class Util implements Serializable 
{ 
    public String currentPageAction() 
    { 
     return FacesContext.getCurrentInstance().getViewRoot().getViewId() + 
        "?faces-redirect=true&includeViewParams=true"; 
    } 
} 

Это надуманный пример на самом деле, как и ожидалось, - в частности, она проходит через исходные значения из просматривать параметры URL-адреса при перенаправлении. Так, например, если исходный URL-адрес равен http://localhost:8080/faces/pages/test.xhtml?foo=bar, когда я нажимаю на <h:commandLink/>, полный URL-адрес, включая параметры представления, выдержит перенаправление.

Проблема в том, что, когда я перехожу от этого надуманного примера к чему-то более реальному (в моем случае, странице поиска), параметры вида не пережить перенаправление.

Вот настоящая страница, для которой она не работает. Извините, это немного длинно для типичного вопроса stackoverflow.

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:ui="http://java.sun.com/jsf/facelets" 
     xmlns:f="http://java.sun.com/jsf/core" 
     xmlns:p="http://primefaces.org/ui" 
     xmlns:search="http://java.sun.com/jsf/composite/components/search" 
     xmlns:oc="http://java.sun.com/jsf/composite/components/mysite" 
     xmlns:fn="http://www.mysite.com.au/jsf"> 
    <h:head> 
     <title></title> 
    </h:head> 
    <h:body> 
     <ui:composition template="/WEB-INF/templates/myLayout.xhtml"> 
      <ui:define name="metadata"> 
       <f:metadata> 
        <f:viewParam name="address" value="#{searchBean.address}"/> 
        <f:viewParam name="lng" value="#{searchBean.longitude}" required="#{!facesContext.postback}" requiredMessage="Longitude is required" validatorMessage="Longitude is invalid"> 
         <f:validateDoubleRange minimum="-180" maximum="180"/> 
        </f:viewParam> 
        <f:viewParam name="lat" value="#{searchBean.latitude}" required="#{!facesContext.postback}" requiredMessage="Latitude is required" validatorMessage="Latitude is invalid"> 
         <f:validateDoubleRange minimum="-90" maximum="90"/> 
        </f:viewParam> 
        <f:viewParam name="gender" value="#{searchBean.gender}"/> 
        <f:viewParam name="language" value="#{searchBean.spokenLanguageId}"/> 
        <f:viewParam name="service" value="#{searchBean.serviceId}"/> 
        <f:viewParam name="rangeKm" value="#{searchBean.rangeKm}" validatorMessage="Range (km) is invalid"> 
         <f:validateLongRange minimum="1"/> 
        </f:viewParam> 
        <f:viewParam name="weeksOffset" value="#{searchBean.weeksOffset}"/> 
        <f:event type="preRenderView" listener="#{searchBean.preRender(e)}"/> 
       </f:metadata> 
      </ui:define> 
      <ui:define name="windowTitle">#{searchBean.address}</ui:define> 
      <ui:define name="scripts"> 
       <script type="text/javascript"> 
        var mysite = mysite || {}; 
        mysite.longitude  = #{searchBean.longitude}; 
        mysite.latitude  = #{searchBean.latitude}; 
        mysite.defaultAddress = "#{applicationBean.defaultAddress}"; 
        mysite.region   = "#{applicationBean.region}"; 
        mysite.baseUrl  = "#{applicationBean.baseUrl}"; 
       </script> 
       <h:outputScript library="javascript" name="map2.js"/> 
       <h:outputScript name="geocode.js" library="javascript" target="head"/> 
       <h:outputScript name="search.js" library="javascript" target="head"/> 
      </ui:define> 

      <ui:define name="rightSidebar"> 
       <div class="ocSearch_sidebarSection"> 
        <oc:map styleClass="search"/> 
        <div> 
         <a style="font-size:11px;text-decoration:underline;" href="#" onclick="mysite.resetMap();return false;">Reset</a> 
        </div> 
       </div> 

       <oc:context-menu-container isFirstChild="false"> 
        <oc:context-menu title="Search Options"> 
         <form id="searchForm" method="get" onsubmit="return mysite.geocode(this);"> 
          <div style="clear:both;float:left;"> 
           <label for="ocSearchRadius">Service Providers within</label> 
           <div id="ocSearchRadius"> 
            <input type="text" id="ocRangeKm" name="rangeKm" value="#{searchBean.rangeKm}" style="width:20px;float:left;"/> 
            <div style="width:40px;margin-top:5px;float:left;overflow:hidden;text-align:center;vertical-align:bottom;">km of</div> 
            <input type="text" id="ocAddress" name="address" value="#{searchBean.address}" style="width:104px;float:left;"/> 
           </div> 
          </div> 
          <div style="float:left;"> 
           <div style="width:60px;margin-right:10px;float:left;"> 
            <label for="ocGender" style="display:block;">Gender</label> 
            <select id="ocGender" name="gender" style="width:50px;"> 
             <h:panelGroup rendered="#{searchBean.gender eq 'any'}"> 
              <option value="any" selected="selected">Any</option> 
              <option value="female">Female</option> 
              <option value="male">Male</option> 
             </h:panelGroup> 
             <h:panelGroup rendered="#{searchBean.gender eq 'female'}"> 
              <option value="any">Any</option> 
              <option value="female" selected="selected">Female</option> 
              <option value="male">Male</option> 
             </h:panelGroup> 
             <h:panelGroup rendered="#{searchBean.gender eq 'male'}"> 
              <option value="any">Any</option> 
              <option value="female">Female</option> 
              <option value="male" selected="selected">Male</option> 
             </h:panelGroup> 
            </select> 
           </div> 
           <div style="float:left;"> 
            <label for="ocLanguage">Language</label> 
            <select id="ocLanguage" name="language" style="width:176px;"> 
             <ui:repeat value="#{commonRequestBean.spokenLanguageItems}" var="item"> 
              <h:panelGroup rendered="#{searchBean.spokenLanguageId eq item.value}"> 
               <option value="#{item.value}" selected="yes">#{item.label}</option> 
              </h:panelGroup> 
              <h:panelGroup rendered="#{searchBean.spokenLanguageId ne item.value}"> 
               <option value="#{item.value}">#{item.label}</option> 
              </h:panelGroup> 
             </ui:repeat> 
            </select> 
           </div> 
          </div> 
          <div style="float:left;"> 
           <label for="ocService">Reason for visit</label> 
           <select id="ocService" name="service" style="width:176px;" > 
            <ui:repeat value="#{commonRequestBean.serviceItems}" var="item"> 
             <h:panelGroup rendered="#{searchBean.serviceId eq item.value}"> 
              <option value="#{item.value}" selected="yes">#{item.label}</option> 
             </h:panelGroup> 
             <h:panelGroup rendered="#{searchBean.serviceId ne item.value}"> 
              <option value="#{item.value}">#{item.label}</option> 
             </h:panelGroup> 
            </ui:repeat> 
           </select> 
          </div> 

          <div style="float:left;"> 
           <label for="ocStartDate">From</label> 
           <select id="ocStartDate" name="weeksOffset" style="width:176px;"> 
            <ui:repeat value="#{fn:selectableDates(13)}" var="date" varStatus="dateStatus"> 
             <h:panelGroup rendered="#{date.value eq searchBean.weeksOffset}"> 
              <option value="#{date.value}" selected="yes">#{date.label}</option> 
             </h:panelGroup> 
             <h:panelGroup rendered="#{date.value ne searchBean.weeksOffset}"> 
              <option value="#{date.value}">#{date.label}</option> 
             </h:panelGroup> 
            </ui:repeat> 
           </select> 
          </div> 

          <div style="margin-top:8px;float:left;"> 
           <p:button id="searchAgainButton" value="Search Again"/> 
           <script type="text/javascript"> 
            //<![CDATA[ 
            $(function(){ 
             // Replace the Search Again button with a clone whose type is submit. 
             var oldButton = $('#searchAgainButton'); 
             var newButton = oldButton.clone(true); 
             newButton.attr("type","submit"); 
             newButton.attr("id","searchAgainButtonClone"); 
             newButton.removeAttr("onclick"); 
             newButton.insertBefore(oldButton); 
             oldButton.remove(); 
             newButton.attr("id","searchAgainButton"); 
            }); 
            //]]> 
           </script> 
          </div> 

          <input type="hidden" id="ocLng"  name="lng"  value="#{searchBean.longitude}"/> 
          <input type="hidden" id="ocLat"  name="lat"  value="#{searchBean.latitude}"/> 
         </form> 
         <script> 
          // Ensure the form fields are set to the current values. (Webkit bug workaround.) 
          $(function(){ 
           $('#ocRangeKm').val('#{searchBean.rangeKm}'); 
           $('#ocAddress').val('#{searchBean.address}'); 
           $('#ocGender').val('#{searchBean.gender}'); 
           $('#ocLanguage').val('#{searchBean.spokenLanguageId}'); 
           $('#ocService').val('#{searchBean.serviceId}'); 
           $('#ocStartDate').val('#{searchBean.weeksOffset}'); 
          }); 
         </script> 
        </oc:context-menu> 
       </oc:context-menu-container> 
      </ui:define> 

      <ui:define name="content"> 
       <div id="ocSearchResultsHeader" class="fixed"> 
        <div style="margin-left:10px;"> 
         <h3 style="margin:8px 0 4px 0;">#{searchBean.searchResultsTitle}</h3> 
         <span class="help">Click a time to book #{searchBean.service.indefiniteArticle} #{searchBean.service.name}</span> 
        </div> 
       </div> 
       <div class="ocSearch_resultSet"> 
        <h:form> 
         <h:commandLink value="Foobar" action="#{util.currentPageAction}"/> 
        </h:form> 
        <search:result resultSet="#{searchBean.results}" startDate="#{searchBean.startDate}"/> 
       </div> 
      </ui:define> 
     </ui:composition> 
    </h:body> 
</html> 

Основополагающий фасоли, searchBean, является запросом областью действия так же, как надуманный пример.

Обновление: Если я удалю экземпляр составного компонента <search:result/>, он теперь работает. Это совершенно неожиданно. Аналогично, если я оставлю экземпляр компонента там и вырезаю тело самого компонента, он работает. Таким образом, в компоненте есть что-то, что мешает чему-то другому. Weird. Я посмотрю, смогу ли я понять, что это такое.

Обновление: Это похоже на ошибку. Если я заменю композитный компонент на это:

<ui:repeat value="#{searchBean.results} var="item" varStatus="itemStatus"> 
    <h:outputText value="#{item.mapMarker}"/> 
    <br/> 
</ui:repeat> 

он также терпит неудачу, как и для композитного компонента.

Точно так же это не удается:

<h:dataTable value="#{searchBean.results}" var="item"> 
    <h:column> 
     <h:outputText value="#{item.mapMarker}"/> 
     <br/> 
    </h:column> 
</h:dataTable> 

В моем конкретном случае, есть три результата, так что я могу перебрать их вручную, как например:

<ui:param name="results" value="#{searchBean.results}"/> 
<br/> 
<h:outputText value="#{results.get(0).mapMarker}"/> 
<br/> 
<h:outputText value="#{results.get(1).mapMarker}"/> 
<br/> 
<h:outputText value="#{results.get(2).mapMarker}"/> 
<br/> 

и она работает.

Так что есть что-то об итерации по результатам, которые завинчиваются с помощью <h:commandLink/>.

Что может произойти неправильно? Еще одна ошибка Mojarra, где простой случай использования терпит неудачу?

Окончательное обновление: Сузили проблему с надуманными примерами и переместили вопрос here.

+0

Извините @BalusC - Я вижу, что вы удалили свой ответ. У меня проблема была прибита - см. Ссылку в «Окончательное обновление». –

+0

Я удалил его, потому что он не ответил на ваш вопрос :) Не стесняйтесь удалять текущий вопрос, а также он слишком широк. Ваш новый вопрос намного лучше. – BalusC

+0

Мой новый вопрос * слегка * неправильный. Но это делает его еще проще. Исправлена. –

ответ

1

Это сумасшедшая ошибка, и я не могу понять, является ли это JDK7, Mojarra, контейнер EJB, GlassFish вообще или просто плохой комбинацией из двух или более из них.

Рассмотрим следующий фрагмент из SearchBean:

public List<NormalizedSearchResult> getResults() 
{ 
    return searchEjb.findByLocation(getRangeKm(), 
            getLongitude(), 
            getLatitude(), 
            gender, 
            getSpokenLanguageId(), 
            getServiceId(), 
            1, 
            99, 
            getStartDate().toDateMidnight().toDate(), 
            7); 
} 

public List<NormalizedSearchResult> getResults2() 
{ 
    float lng = longitude; 
    float lat = latitude; 
    return searchEjb.findByLocation(getRangeKm(), 
            lng, 
            lat, 
            gender, 
            getSpokenLanguageId(), 
            getServiceId(), 
            1, 
            99, 
            getStartDate().toDateMidnight().toDate(), 
            7); 
} 

public List<NormalizedSearchResult> getResults3() 
{ 
    float lng = getLongitude(); 
    float lat = getLatitude(); 
    return searchEjb.findByLocation(getRangeKm(), 
            lng, 
            lat, 
            gender, 
            getSpokenLanguageId(), 
            getServiceId(), 
            1, 
            99, 
            getStartDate().toDateMidnight().toDate(), 
            7); 
} 

public List<NormalizedSearchResult> getResults4() 
{ 
    float lng = longitude; 
    float lat = latitude; 
    return searchEjb.findByLocation(getRangeKm(), 
            138.5999594f, 
            -34.9286212f, 
            gender, 
            getSpokenLanguageId(), 
            getServiceId(), 
            1, 
            99, 
            getStartDate().toDateMidnight().toDate(), 
            7); 
} 

public List<NormalizedSearchResult> getResults5() 
{ 
    float lng = 138.5999594f; 
    float lat = -34.9286212f; 
    return searchEjb.findByLocation(getRangeKm(), 
            lng, 
            lat, 
            gender, 
            getSpokenLanguageId(), 
            getServiceId(), 
            1, 
            99, 
            getStartDate().toDateMidnight().toDate(), 
            7); 
} 

public Float getLongitude() 
{ 
    return longitude; 
} 

public void setLongitude(Float longitude) 
{ 
    this.longitude = longitude; 
} 

public Float getLatitude() 
{ 
    return latitude; 
} 

public void setLatitude() 
{ 
    this.latitude = latitude; 
} 

private Float longitude; 
private Float latitude; 

Любой из этих фрагментах, когда он включен в search.xhtml, вызывают includeViewParams=true сбой на вышеназванного <h:commandLink/>:

<ui:repeat value="#{searchBean.results}"/> 
<ui:repeat value="#{searchBean.results2}"/> 
<ui:repeat value="#{searchBean.results3}"/> 
<ui:repeat value="#{searchBean.results4}"/> 

Однако этот один не имеет такой же нежелательный эффект:

<ui:repeat value="#{searchBean.results5}"/> 

Нор делает это:

<ui:param name="results" value="#{pageBean.results}"/> 
<h:outputText value="#{results.get(0).mapMarker}"/> 
<br/> 
<h:outputText value="#{results.get(1).mapMarker}"/> 
<br/> 
<h:outputText value="#{results.get(2).mapMarker}"/> 
<br/> 

И, конечно же, includeViewParams=true работы, когда ни один из этих Xhtml фрагменты не используются ,

Затем я изменил тип на longitude и latitude частных переменных от Float к float и больше не был эти ошибки для любого из вышеперечисленных случаев.

WTF ?! Шутки в сторону?

Как мог кто-нибудь предположить, что параметры отображения unboxing во время предыдущих этапов визуализации представления будут разбиты на includeViewParams=true?

Комментарии к JAVASERVERFACES-2260.