2015-12-14 14 views
1

我正在运行Tomcat 7,JSF 2.2,OpenWebBeans 1.6,Omnifaces 1.8和Richfaces 3.我最近添加了Omnifaces CombinedResourceHandler,并且注意到,当页面上的表单被提交时,尽管该方法位于未渲染的块中,但它会导致调用数据表的值方法。使用Richfaces和Omnifaces CombinedResourceHandler导致h:dataTable值方法被调用,尽管呈现=“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()。这似乎只影响h:dataTable组件的value属性。其他el表达式不会被调用。

我设置了以下Maven dependices一个小样本项目:

<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作为依赖项。我没有任何JavaScript合并。如果我禁用Omnifaces CRH或从pom文件中删除Richfaces,它将按预期工作。

我尝试使用Richfaces 5,但我在那里得到了类似的行为(尽管getter被调用的次数更少)。我没有尝试过最新的Omnifaces版本,因为它与OWB 1.6不兼容。

Anoter的兴趣点可能是如果我用JSTL <c:if>包围数据表,它就可以工作。但我不想这样做,显然...

我在这里做错了什么?这些版本的Omnifaces CRH和Richfaces之间是否存在兼容性问题?

编辑:从数据表中的getter

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被报废),不是我认为它有帮助。调用getter当然是不必要的,但它是否会导致任何问题? – Makhiel

+0

想我也应该回复你!即使我们修复了糟糕构建的getter,如果@PostConstructs被调用的次数比预期的多,也可能导致性能问题。不太可能是一个大问题......但它感觉非常没有必要。 – Robin

回答

1

首先的调用堆栈,getter方法不应该执行业务逻辑: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本身并没有这样做。至少,不直接。它只处理组件树中的组件资源。然而,为了提取自己开发的资源库方法,它具有一个RichFaces专用的hack。尽管如此,它的source code似乎并没有触发任何地方的visitTree()。要确定真正的原因,只需在getter方法上放置一个调试断点并探索负责调用的调用堆栈。

至于明显的JSTL <c:if>厌恶(这个词“明明”是有点太强大了这里),这是食品读:JSTL in JSF2 Facelets... makes sense?

也就是说,最新OmniFaces的1.x版本是1.8.3 ,而不是1.8。另请参阅download部分。将Mojarra升级到现在的最新版本2.2.12也是值得的。

+0

感谢您的回复。我知道getters不应该执行业务逻辑。有一些遗留代码做它不应该做的事情,我没有解决这个问题的地方。我更多地要求防止类似的事情发生意外。 看起来好像UIComponent#visitTree()实际上在调用堆栈中。从我可以告诉,它不考虑SKIP_UNRENDERED。似乎并不像OmniFaces在那里......我用调用堆栈更新了我的帖子。有任何想法吗? – Robin

+0

对,这是由Facelets'FaceletViewHandlingStrategy.reapplyDynamicActions'完成的。这将在重建动态操作视图(CRH删除组件)期间发生。我只想知道为什么在渲染响应期间重建视图。这通常是不必要的。也许你正在使用POST而不是GET导航到不同的视图? – BalusC

+0

在我的小测试应用程序,我只是有一个commandButton和数据表的视图。当方法运行时,FacesContext至少仍然认为它正在做回发。 但是有点好奇......我可以按下commandButton一次,而不用调用未提及的方法。当我不止一次地做到这一点时,也就是说,如果我不断回复相同的观点。如果我完全刷新页面(例如,只需再次通过url导航到该页面),它将重新开始,只需点击一下按钮,其余的就会触发此行为。 – Robin

相关问题