2015-12-14 11 views
1

Я запускаю Tomcat 7, JSF 2.2, OpenWebBeans 1.6, Omnifaces 1.8 и Richfaces 3. Недавно я добавил Omnifaces CombinedResourceHandler, и заметил, что он вызывает метод значения datatable, несмотря на то, что метод находится в незагруженном блоке, когда отправляется форма на странице.Использование Richfaces и Omnifaces CombinedResourceHandler приводит к h: метод valueTable получает вызов несмотря на rendered = "false"

Пример:

<h:body styleClass="bdyPage"> 
    <h:form id="form"> 
     <h:commandButton value="test button" /> 
     <h:panelGroup rendered="false"> 
      <h:outputText value="#{testBean.getTestString()}" /> 
      <h:dataTable id="testtable22" value="#{testBean.strings}" var="str" 
       rowClasses="odd, even"> 
       <h:column> 
        <f:facet name="header"> 
         test 
        </f:facet> 
        <h:outputText value="str" /> 
       </h:column> 
      </h:dataTable> 
     </h:panelGroup> 
    </h:form> 
</h:body> 

У меня есть простой тест фасоли:

@Named("testBean") 
@RequestScoped 
public class TestBean1 implements Serializable { 

    private static final long serialVersionUID = 1L; 

    public String getTestString() { 
     System.out.println("Test string"); 
     return "test string"; 
    } 

    public List<String> getStrings() { 
     List<String> strings = new ArrayList<String>(); 
     strings.add("hej"); 
     strings.add("hejsan"); 
     strings.add("hej hej!"); 
     System.out.println("getting strings"); 
     return strings; 
    } 

} 

Обычно getStrings() не вызывается, потому что panelGroup установлен в положение не может быть оказана. Однако, когда я запускаю и Omnifaces CombinedResourceHandler и Richfaces, getStrings() вызывается, когда кнопка отправки нажата более одного раза. Это только влияет на атрибут value компонента h: dataTable. Другие выражения el не вызываются.

Я создал небольшой пример проект со следующим dependices Maven:

<dependencies> 
    <dependency> 
     <groupId>org.richfaces.ui</groupId> 
     <artifactId>richfaces-components-ui</artifactId> 
     <version>4.3.7.Final</version> 
    </dependency> 
    <dependency> 
     <groupId>org.richfaces.core</groupId> 
     <artifactId>richfaces-core-impl</artifactId> 
     <version>4.3.7.Final</version> 
    </dependency> 
<!-- <dependency> 
    <groupId>org.richfaces</groupId> 
    <artifactId>richfaces</artifactId> 
    <version>5.0.0.Alpha3</version> 
</dependency> 
    --> 
    <dependency> 
     <groupId>javax.validation</groupId> 
     <artifactId>validation-api</artifactId> 
     <version>1.0.0.GA</version> 
     <type>jar</type> 
     <classifier>sources</classifier> 
    </dependency> 
    <dependency> 
     <groupId>javax.validation</groupId> 
     <artifactId>validation-api</artifactId> 
     <version>1.0.0.GA</version> 
     <type>jar</type> 
    </dependency> 
    <dependency> 
     <groupId>org.omnifaces</groupId> 
     <artifactId>omnifaces</artifactId> 
     <version>1.8</version> 
    </dependency> 
    <dependency> 
     <groupId>javax.enterprise</groupId> 
     <artifactId>cdi-api</artifactId> 
     <version>1.2</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.openwebbeans</groupId> 
     <artifactId>openwebbeans-impl</artifactId> 
     <version>1.6.2</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.openwebbeans</groupId> 
     <artifactId>openwebbeans-jsf</artifactId> 
     <version>1.6.2</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.openwebbeans</groupId> 
     <artifactId>openwebbeans-el22</artifactId> 
     <version>1.6.2</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.openwebbeans</groupId> 
     <artifactId>openwebbeans-web</artifactId> 
     <version>1.6.2</version> 
    </dependency> 
    <dependency> 
     <groupId>org.glassfish</groupId> 
     <artifactId>javax.faces</artifactId> 
     <version>2.2.6</version> 
    </dependency> 
</dependencies> 

Я не использую никаких RichFaces компонентов в проекте или на тестовой странице. Я просто включаю Richfaces как зависимость. У меня нет javascripts, которые объединяются. Если я отключу Omnifaces CRH или удалю Richfaces из файла pom, он работает так, как ожидалось.

Я попытался использовать Richfaces 5, но я получаю подобное поведение (хотя геттер называется меньше). Я не пробовал последнюю версию Omnifaces, так как она несовместима с OWB 1.6.

Anoter point of interest может отличаться от того, что если я окружаю данные с помощью JSTL <c:if>, он работает. Но я не хочу этого делать, очевидно ...

Я делаю что-то неправильно здесь? Есть ли проблема совместимости между этими версиями Omnifaces CRH и Richfaces?

Edit: Стек вызовов из геттер в DataTable в

TestBean1.getStrings() line: 33 
TestBean1$$OwbNormalScopeProxy0.getStrings() line: not available  
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
NativeMethodAccessorImpl.invoke(Object, Object[]) line: not available 
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: not available 
Method.invoke(Object, Object...) line: not available  
BeanELResolver.getValue(ELContext, Object, Object) line: 87 
DemuxCompositeELResolver._getValue(int, ELResolver[], ELContext, Object, Object) line: 176 
DemuxCompositeELResolver.getValue(ELContext, Object, Object) line: 203 
AstValue.getValue(EvaluationContext) line: 183 
ValueExpressionImpl.getValue(ELContext) line: 185 
WrappedValueExpression.getValue(ELContext) line: 70 
TagValueExpression.getValue(ELContext) line: 109  
ComponentStateHelper.eval(Serializable, Object) line: 194 
ComponentStateHelper.eval(Serializable) line: 182 
HtmlDataTable(UIData).getValue() line: 732 
HtmlDataTable(UIData).getDataModel() line: 1822 
HtmlDataTable(UIData).setRowIndexWithoutRowStatePreserved(int) line: 484  
HtmlDataTable(UIData).setRowIndex(int) line: 473  
HtmlDataTable(UIData).visitColumnsAndColumnFacets(VisitContext, VisitCallback, boolean) line: 2104 
HtmlDataTable(UIData).visitTree(VisitContext, VisitCallback) line: 1446 
HtmlPanelGroup(UIComponent).visitTree(VisitContext, VisitCallback) line: 1701 
HtmlForm(UIComponent).visitTree(VisitContext, VisitCallback) line: 1701 
HtmlForm(UIForm).visitTree(VisitContext, VisitCallback) line: 371 
HtmlBody(UIComponent).visitTree(VisitContext, VisitCallback) line: 1701 
UIViewRoot(UIComponent).visitTree(VisitContext, VisitCallback) line: 1701 
FaceletViewHandlingStrategy.locateComponentByClientId(FacesContext, String) line: 2082 
FaceletViewHandlingStrategy.reapplyDynamicRemove(FacesContext, ComponentStruct) line: 2174 
FaceletViewHandlingStrategy.reapplyDynamicActions(FacesContext) line: 2116 
FaceletViewHandlingStrategy.buildView(FacesContext, UIViewRoot) line: 966 
RenderResponsePhase.execute(FacesContext) line: 99 
RenderResponsePhase(Phase).doPhase(FacesContext, Lifecycle, ListIterator<PhaseListener>) line: 101 
LifecycleImpl.render(FacesContext) line: 219  
FacesServlet.service(ServletRequest, ServletResponse) line: 647 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 305 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210 
StandardWrapperValve.invoke(Request, Response) line: 222  
StandardContextValve.invoke(Request, Response) line: 123  
NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 472  
StandardHostValve.invoke(Request, Response) line: 171 
ErrorReportValve.invoke(Request, Response) line: 99 
AccessLogValve.invoke(Request, Response) line: 936 
StandardEngineValve.invoke(Request, Response) line: 118 
CoyoteAdapter.service(Request, Response) line: 407 
Http11Processor(AbstractHttp11Processor).process(SocketWrapper<S>) line: 1004 
Http11Protocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler).process(SocketWrapper<S>, SocketStatus) line: 589  
JIoEndpoint$SocketProcessor.run() line: 312 
ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: not available 
ThreadPoolExecutor$Worker.run() line: not available 
TaskThread(Thread).run() line: not available [local variables unavailable] 
+1

Последняя версия RichFaces - это 4.5.11.Final (5.x была отменена), а не то, что я думаю, что это помогает. Вызов геттера, безусловно, не нужен, но вызывает ли это какие-либо проблемы? – Makhiel

+0

Фигурное я должен ответить вам также! Даже если мы исправим плохо сконструированные геттеры, это может привести к проблемам с производительностью, если @PostConstructs вызывается чаще, чем ожидалось. Скорее всего, это будет огромная проблема ... но это кажется очень ненужным. – Robin

ответ

1

Прежде всего, методы геттерные не должны выполнять бизнес-логику: How and when should I load the model from database for h:dataTable. Как только вы исправите метод getter, чтобы полностью вернуть свойство, беспокойство о том, что он называется несколько раз, становится совершенно ненужным.

Возвращаясь к наблюдаемому поведению, метод Поглотителя по нетонированным <h:dataTable> может быть вызван в «неожиданные» времена, когда код выполняет UIComponent#visitTree() без VisitHint#SKIP_UNRENDERED и/или VisitHint#SKIP_ITERATION. Сам CombinedResourceHandler этого не делает. По крайней мере, не напрямую. Он управляет только ресурсами компонента в дереве компонентов. Тем не менее, у него есть специальный RichTaces hack, чтобы извлечь свой подход к ресурсной библиотеке. Тем не менее, его source code, похоже, не запускает visitTree() в любом месте. Чтобы прикрыть реальную причину, просто поставьте точку останова отладки на метод getter и исследуйте стек вызовов, который отвечает за вызов.

Как кажущейся JSTL <c:if> неприятия (слово «очевидно» является слишком сильным здесь), это пища для чтения: JSTL in JSF2 Facelets... makes sense?

Тем не менее, последний релиз OmniFaces 1.x является 1.8.3 , а не 1.8. См. Также раздел download. Было бы также целесообразно обновить Мохарру до последней, которая сейчас 2.2.12.

+0

Спасибо за ответ. Я знаю, что геттеры не должны выполнять бизнес-логику. Есть какой-то унаследованный код, делающий то, чего он не должен, и у меня нет проблем с этим, где я его нашел. Я просил больше предупредить, что что-то подобное произойдет неожиданно. Кажется, что UIComponent # visitTree() находится в стеке вызовов, на самом деле. Из того, что я могу сказать, он не учитывает SKIP_UNRENDERED. Кажется, это не так, как если бы OmniFaces там ... Я обновил свой пост с помощью стека вызовов. Есть идеи? – Robin

+0

Правильно, это делается Facelets 'FaceletViewHandlingStrategy.reapplyDynamicActions'. Это произойдет при восстановлении динамически управляемого представления (CRH удаляет компоненты). Мне только интересно, почему представление перестраивается во время ответа рендера. Обычно это не нужно. Возможно, вы переходите к другому виду, используя POST вместо GET? – BalusC

+0

В моем маленьком тестовом приложении у меня просто есть представление с commandButton и datatable. Когда метод запускается как незагруженный, FacesContext по крайней мере по-прежнему полагает, что он выполняет обратную передачу. Но это немного любопытно ... Я могу нажать commandButton один раз без вызова непереданного метода. Это когда я делаю это несколько раз, что он работает, то есть, если я продолжаю делать обратные передачи в одном представлении. Если я полностью обновляю страницу (например, просто перейдя на нее с помощью URL-адреса снова), она начинается с одной щелчком мыши, а остальные запускают это поведение. – Robin