|
I'm having the same issue. I've paired down a page with two forms to the following minimal version that breaks:
<%@ taglib uri="/webwork" prefix="ww" %> <ww:form action="/searchVacations.action" name="searchVacationsForm" method="GET"> <ww:select id="airhotel_roomCount" name="roomCount" list="{1, 2, 3}" /> </ww:form> <ww:form action="/searchHotels.action" name="searchHotelsForm" method="GET"> </ww:form> which results in the stacktrace: java.lang.StackOverflowError at java.util.HashMap.hash(HashMap.java:264) at java.util.HashMap.containsKey(HashMap.java:342) at ognl.OgnlContext.get(OgnlContext.java:378) at com.opensymphony.webwork.components.Component.getComponentStack(Component.java:58) at com.opensymphony.webwork.components.Component.findAncestor(Component.java:90) at com.opensymphony.webwork.components.UIBean.getTheme(UIBean.java:365) at com.opensymphony.webwork.components.UIBean.getTheme(UIBean.java:367) at com.opensymphony.webwork.components.UIBean.getTheme(UIBean.java:367) at com.opensymphony.webwork.components.UIBean.getTheme(UIBean.java:367) at com.opensymphony.webwork.components.UIBean.getTheme(UIBean.java:367) ... If I remove the line with the ww:select tag, the page renders successfully. I've been experiencing this problem as well. I took a look at the fix, and I suspect that it will fix my problem. I'm not sure if the implementation of the fix is quite right, though. I've stepped through the debugger in trying to track my specific problem down. I believe that the problem is actually that the component stack isn't being updated correctly in the Component class.
Here's my specific case: <ww:form id="dummy"> <ww:radio name="hasAccount" label="Do you have an account?" list="#{'yes' : 'Yes', 'no' : 'No'}" value="'yes'" /> </ww:form> <ww:form action="register" method="get"> <ww:hidden name="redirect"/> <ww:submit id="registerSubmit" value="register" /> </ww:form> Here's exactly what's happening with the component stack: <ww:form id="dummy"> - pushes the Form component onto the Component stack <ww:radio .../> - pushes the Radio component onto the Component stack and then pops it off on closing. At this point, the radiomap.ftl template is executed. radiomap.ftl has an embedded ww:iterator tag in it. This causes an IteratorComponent to be created. The Component() constructor pushes the IteratorComponent onto the Component stack correctly. Here's the state of the stack at this point: - IteratorComponent - Form IteratorComponent overrides the end() method from Component. IteratorCompontent.end() does _not_ call super.end(). Thus, the IteratorComponent is not removed from the Component stack (though it should be). I believe this is the root of the problem, but I'll continue the rest of the example for completeness. The stack remains in the state I showed above. Here is the processing for the remainder of the jsp: </ww:form> - pops the top of the Component stack off. Since IteratorComponent did not remove itself from the stack, the IteratorComponent is now removed from the stack, leaving the Form on the stack <ww:form action="register" .../> - Adds the Form to the stack. Then tries to resolve the theme via getTheme(), thus resulting in the infinite recursion. Changing the InteratorComponent to remove itself from the stack on end() would solve my specific problem. I still think there is an issue with Component.findAncestor(), though. It should only start at the current "level" in the stack to prevent the infinite recursion. This would avoid infinite recursion when using nested ww:form tags. Finally, I did a little audit of the Components that override Component.end(). It looks like the following two Components do not call super.end(), and thus may be susceptible to the same problem: ActionComponent ElseIf Each of ActionComponent, ElseIf, and IteratorComponent return false. I suspect that changing "return false;" to the following should correct the problem: return super.end(writer, ""); // use the empty string for the body to prevent anything being written to the output to maintain current functionality The implementation for IteratorComponent isn't quite that easy. I think you would probably want to leave the "return true;" that happens if the iterator has more elements. You'd only want to change the "return false;" when the iterator does not have any more elements. I have only a basic understanding of the WebWork code base, but these are my thoughts based on my initial investigation. Thoughts? FWIW, the current fix did correct the infinite recursion problem for me (as I suspected). Though, I would still recommend investigating my comments above to see if there is a better solution to the problem.
I believe that the following implementation of findAncestor should fix the problem with findAncestor I described above. It will start at the current element in the stack, rather than starting at the top of the stack each time. Granted, findAncestor() is called 8 times, so you may have to check to make sure each invocation of the method will work with this change in functionality. I believe that this implementation is more true to the actual expected behavior of such a method:
public Component findAncestor(Class clazz) { Stack componentStack = getComponentStack(); int start = componentStack.search(this); // subtract 2 from start since start is 1-based for (int i = start - 2; i >= 0; i--) { Component component = (Component) componentStack.get(i); if (clazz.isAssignableFrom(component.getClass()) && component != this) { return component; } } return null; } |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<html>
<ww:form ...>
<ww:textfield ...>
<ww:submit />
</ww:form>
<ww:form ...>
<ww:textfield ...>
<ww:submit />
</ww:form>
</html>
<html>
<ww:form ...>
<ww:textfield ...>
<ww:submit />
</ww:form>
<!-- include2.jsp has a ww:form, ww:textfield and ww:submit -->
<ww:include value="include2.jsp" />
</html>
They seems to be working fine on my side. I suspect it might be my environment (maybe), so i tried it out in quickstart and it seems to be ok as well
Is it possible for you to try it out in quick start ( java -jar webwork-2.2.jar quickstart:showcase to run it) the jsp could go under the webapps/showcase/src/webapp/ directory and they will be accessible through the root context, to see if the problem still persists.
Kindly let us know the results. Cheers! :-)