Stripes

Stack Overflow when using a layout with an existing component name

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Minor Minor
  • Resolution: Fixed
  • Affects Version/s: Release 1.5.6
  • Fix Version/s: Release 1.5.7, Release 1.6
  • Component/s: Tag Library
  • Labels:
    None

Description

I have used this pattern successfully in 1.5.3, but it fails in 1.5.6-SNAPSHOT:

Page:
<s:layout-render name="testlayout.jsp">
<s:layout-component name="pageContent">
HELLO
<s:layout-render name="testinclude.jsp">
<s:layout-component name="pageContent">
INCLUDED
</s:layout-component>
</s:layout-render>
</s:layout-component>
</s:layout-render>

testlayout.jsp:
<s:layout-definition>
LAYOUT
${pageContent}
</s:layout-definition>

testinclude.jsp:
<s:layout-definition>
INCLUDE:
${pageContent}
</s:layout-definition>

The outout I expect is:
LAYOUT HELLO INCLUDE: INCLUDED

The output I get is:
LAYOUT HELLO INCLUDE: HELLO INCLUDE: HELLO INCLUDE: ... repeated until a stack overflow

In this simple test case, renaming the included layout component fixes this problem, but in my actual case it then fails to include anything. I am not sure why that is, but suspect the cause is the same as in this simple case.

Activity

Hide
Ben Gunter added a comment - 22/Apr/11 2:32 PM

This is fixed in r1428 for 1.5.7. I have tested it against the simple case you presented here. Please test 1.5.7-SNAPSHOT in your application and let me know how it goes.

Show
Ben Gunter added a comment - 22/Apr/11 2:32 PM This is fixed in r1428 for 1.5.7. I have tested it against the simple case you presented here. Please test 1.5.7-SNAPSHOT in your application and let me know how it goes.
Hide
Peter Mahoney added a comment - 27/Apr/11 4:29 AM

The stack overflow is certainly fixed, thanks. However, I am not getting the real page rendering correctly. I have put together a simple test case:

Page:
<s:layout-render name="testlayout.jsp">
<s:layout-component name="pageContent">
HELLO
</s:layout-component>
</s:layout-render>

testlayout.jsp:
<s:layout-definition>
LAYOUT-START
<s:layout-render name="testlayout2.jsp">
<s:layout-component name="pageContent">
<s:layout-render name="testinclude.jsp">
<s:layout-component name="pageContent">
${pageContent}
</s:layout-component>
</s:layout-render>
</s:layout-component>
</s:layout-render>
LAYOUT-END
</s:layout-definition>

testlayout2.jsp:
<s:layout-definition>
INNER-START
<s:layout-component name="pageContent" />
INNER-END
</s:layout-definition>

testinclude.jsp:
<s:layout-definition>
INCLUDE:
${pageContent}
</s:layout-definition>

The output I expect is:
LAYOUT-START INNER-START INCLUDE: HELLO INNER-END LAYOUT-END

The output I get is:
LAYOUT-START INNER-START INCLUDE: INNER-END LAYOUT-END

Show
Peter Mahoney added a comment - 27/Apr/11 4:29 AM The stack overflow is certainly fixed, thanks. However, I am not getting the real page rendering correctly. I have put together a simple test case: Page: <s:layout-render name="testlayout.jsp"> <s:layout-component name="pageContent"> HELLO </s:layout-component> </s:layout-render> testlayout.jsp: <s:layout-definition> LAYOUT-START <s:layout-render name="testlayout2.jsp"> <s:layout-component name="pageContent"> <s:layout-render name="testinclude.jsp"> <s:layout-component name="pageContent"> ${pageContent} </s:layout-component> </s:layout-render> </s:layout-component> </s:layout-render> LAYOUT-END </s:layout-definition> testlayout2.jsp: <s:layout-definition> INNER-START <s:layout-component name="pageContent" /> INNER-END </s:layout-definition> testinclude.jsp: <s:layout-definition> INCLUDE: ${pageContent} </s:layout-definition> The output I expect is: LAYOUT-START INNER-START INCLUDE: HELLO INNER-END LAYOUT-END The output I get is: LAYOUT-START INNER-START INCLUDE: INNER-END LAYOUT-END
Hide
Ben Gunter added a comment - 27/Apr/11 2:34 PM

New revision 1438 fixes this for the test case described above. Please test against the latest snapshot once it has built and deployed.

Show
Ben Gunter added a comment - 27/Apr/11 2:34 PM New revision 1438 fixes this for the test case described above. Please test against the latest snapshot once it has built and deployed.
Hide
Peter Mahoney added a comment - 03/May/11 8:39 AM

It is getting better, but there are still page elements missing. A revised test case is:

Page:
<s:layout-render name="testlayout.jsp">
<s:layout-component name="pageContent">
HELLO
<s:layout-render name="testlayout3.jsp" />
</s:layout-component>
</s:layout-render>

testlayout3.jsp:
<s:layout-definition>
AGAIN
</s:layout-definition>

The output I expect is:
LAYOUT-START INNER-START INCLUDE: HELLO AGAIN INNER-END LAYOUT-END

The output I get is:
LAYOUT-START INNER-START INCLUDE: HELLO INNER-END LAYOUT-END

Show
Peter Mahoney added a comment - 03/May/11 8:39 AM It is getting better, but there are still page elements missing. A revised test case is: Page: <s:layout-render name="testlayout.jsp"> <s:layout-component name="pageContent"> HELLO <s:layout-render name="testlayout3.jsp" /> </s:layout-component> </s:layout-render> testlayout3.jsp: <s:layout-definition> AGAIN </s:layout-definition> The output I expect is: LAYOUT-START INNER-START INCLUDE: HELLO AGAIN INNER-END LAYOUT-END The output I get is: LAYOUT-START INNER-START INCLUDE: HELLO INNER-END LAYOUT-END
Hide
Peter Mahoney added a comment - 08/Aug/11 3:14 AM

The problem described by the last test case is still an issue for us, as it is preventing upgrading to any version later than 1.5.3 to fix the memory problems that layout streaming fixes.

Show
Peter Mahoney added a comment - 08/Aug/11 3:14 AM The problem described by the last test case is still an issue for us, as it is preventing upgrading to any version later than 1.5.3 to fix the memory problems that layout streaming fixes.
Hide
Ben Gunter added a comment - 06/Feb/12 1:56 PM

Peter, I just committed a fix for the most recent example. Please test against the most recent snapshot.

Show
Ben Gunter added a comment - 06/Feb/12 1:56 PM Peter, I just committed a fix for the most recent example. Please test against the most recent snapshot.
Hide
Peter Mahoney added a comment - 08/Feb/12 5:15 AM

Thanks for the update. There still appears to be a problem. I am getting a NPE:

root cause

java.lang.NullPointerException
net.sourceforge.stripes.tag.layout.LayoutContext.lookup(LayoutContext.java:85)
net.sourceforge.stripes.tag.layout.LayoutComponentRenderer.toString(LayoutComponentRenderer.java:173)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
java.util.AbstractMap.toString(AbstractMap.java:490)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
net.sourceforge.stripes.tag.layout.LayoutContext.toString(LayoutContext.java:269)
net.sourceforge.stripes.tag.layout.LayoutRenderTag.doEndTag(LayoutRenderTag.java:181)
...

Here is a testcase to reproduce the problem:

<s:layout-render name="wrapper.jsp">
<s:layout-component name="wrapped">
wrapped
</s:layout-component>
</s:layout-render>

wrapper.jsp:
<s:layout-definition>
<s:layout-render name="wrapper2.jsp">
<s:layout-component name="head">
${head}
<s:layout-render name="included.jsp" />
</s:layout-component>
<s:layout-component name="wrapped">
${wrapped}
</s:layout-component>
</s:layout-render>
</s:layout-definition>

wrapper2.jsp:
<s:layout-definition>
<s:layout-render name="wrapped3.jsp">
<s:layout-component name="head">
${head}
</s:layout-component>
<s:layout-component name="wrapped">
${wrapped}
</s:layout-component>
</s:layout-render>
</s:layout-definition>

wrapped3.jsp:
<s:layout-definition>
${head}
WRAPPED-START
${wrapped}
WRAPPED-END
</s:layout-definition>

included.jsp:
<s:layout-definition>
included
</s:layout-definition>

I have found that if the included.jsp tag is moved elsewhere e.g. within the "wrapped" layout-component, then the NPE goes away.

Show
Peter Mahoney added a comment - 08/Feb/12 5:15 AM Thanks for the update. There still appears to be a problem. I am getting a NPE: root cause java.lang.NullPointerException net.sourceforge.stripes.tag.layout.LayoutContext.lookup(LayoutContext.java:85) net.sourceforge.stripes.tag.layout.LayoutComponentRenderer.toString(LayoutComponentRenderer.java:173) java.lang.String.valueOf(String.java:2826) java.lang.StringBuilder.append(StringBuilder.java:115) java.util.AbstractMap.toString(AbstractMap.java:490) java.lang.String.valueOf(String.java:2826) java.lang.StringBuilder.append(StringBuilder.java:115) net.sourceforge.stripes.tag.layout.LayoutContext.toString(LayoutContext.java:269) net.sourceforge.stripes.tag.layout.LayoutRenderTag.doEndTag(LayoutRenderTag.java:181) ... Here is a testcase to reproduce the problem: <s:layout-render name="wrapper.jsp"> <s:layout-component name="wrapped"> wrapped </s:layout-component> </s:layout-render> wrapper.jsp: <s:layout-definition> <s:layout-render name="wrapper2.jsp"> <s:layout-component name="head"> ${head} <s:layout-render name="included.jsp" /> </s:layout-component> <s:layout-component name="wrapped"> ${wrapped} </s:layout-component> </s:layout-render> </s:layout-definition> wrapper2.jsp: <s:layout-definition> <s:layout-render name="wrapped3.jsp"> <s:layout-component name="head"> ${head} </s:layout-component> <s:layout-component name="wrapped"> ${wrapped} </s:layout-component> </s:layout-render> </s:layout-definition> wrapped3.jsp: <s:layout-definition> ${head} WRAPPED-START ${wrapped} WRAPPED-END </s:layout-definition> included.jsp: <s:layout-definition> included </s:layout-definition> I have found that if the included.jsp tag is moved elsewhere e.g. within the "wrapped" layout-component, then the NPE goes away.
Hide
Ben Gunter added a comment - 08/Feb/12 9:40 AM

That was an interesting one. Try again with the new snapshot. The NPE is gone and your previous test case still works.

Show
Ben Gunter added a comment - 08/Feb/12 9:40 AM That was an interesting one. Try again with the new snapshot. The NPE is gone and your previous test case still works.
Hide
Peter Mahoney added a comment - 08/Feb/12 10:33 AM

Yes, the NPE is fixed, thanks.

I am however getting a number of instances of content not being rendered. I have not had a chance to create a testcase yet, but an example is:

<s:layout-definition>
<s:layout-component name="pageHead">
</s:layout-component>

<s:layout-component name="pageContent">
<db:fieldPanel titleKey="teacherNamePanelTitle">
HELLO
<s:layout-render name="names.jsp" titleKey="teacherNamePanelTitle" />
</db:fieldPanel>
...

And names.jsp starts:
<s:layout-definition>
AGAIN
...

"HELLO" renders, but "AGAIN" doesn't. I will try to construct a simple testcase as soon as I can.

Show
Peter Mahoney added a comment - 08/Feb/12 10:33 AM Yes, the NPE is fixed, thanks. I am however getting a number of instances of content not being rendered. I have not had a chance to create a testcase yet, but an example is: <s:layout-definition> <s:layout-component name="pageHead"> </s:layout-component> <s:layout-component name="pageContent"> <db:fieldPanel titleKey="teacherNamePanelTitle"> HELLO <s:layout-render name="names.jsp" titleKey="teacherNamePanelTitle" /> </db:fieldPanel> ... And names.jsp starts: <s:layout-definition> AGAIN ... "HELLO" renders, but "AGAIN" doesn't. I will try to construct a simple testcase as soon as I can.
Hide
Peter Mahoney added a comment - 09/Feb/12 2:23 AM

I think I have narrowed down the problem. It is where we have layout definitions which contain layout components which contain default content e.g.

<s:layout-definition>
<s:layout-component name="pageHead">
This is some default content
</s:layout-component>
</s:layout-definition>

In 1.5.3, the default content would be rendered if not overridden in the layout-render. In 1.5.7-SNAPSHOT, the default content is not rendered at all. Is this an intended change? I can generally work around this limitation, if necessary.

Show
Peter Mahoney added a comment - 09/Feb/12 2:23 AM I think I have narrowed down the problem. It is where we have layout definitions which contain layout components which contain default content e.g. <s:layout-definition> <s:layout-component name="pageHead"> This is some default content </s:layout-component> </s:layout-definition> In 1.5.3, the default content would be rendered if not overridden in the layout-render. In 1.5.7-SNAPSHOT, the default content is not rendered at all. Is this an intended change? I can generally work around this limitation, if necessary.
Hide
Peter Mahoney added a comment - 10/Feb/12 3:46 AM

I have found a new problem, when using a forEach loop:

<c:forEach var="word" items="${actionBean.words}">
<s:layout-render name="wrapper.jsp">
<s:layout-component name="wrapped">
${word}
</s:layout-component>
</s:layout-render>
</c:forEach>

wrapper.jsp:
<s:layout-definition>
${wrapped}
</s:layout-definition>

public List<String> getWords() { return Arrays.asList("dog", "cat", "fish", "banana"); }

getWords() is called 5 times, and the output is:
dog dog dog dog

Show
Peter Mahoney added a comment - 10/Feb/12 3:46 AM I have found a new problem, when using a forEach loop: <c:forEach var="word" items="${actionBean.words}"> <s:layout-render name="wrapper.jsp"> <s:layout-component name="wrapped"> ${word} </s:layout-component> </s:layout-render> </c:forEach> wrapper.jsp: <s:layout-definition> ${wrapped} </s:layout-definition> public List<String> getWords() { return Arrays.asList("dog", "cat", "fish", "banana"); } getWords() is called 5 times, and the output is: dog dog dog dog
Hide
Ben Gunter added a comment - 10/Feb/12 8:00 AM

Try passing the word as a parameter to the render: <s:layout-render name="wrapped" word="${word}">

Show
Ben Gunter added a comment - 10/Feb/12 8:00 AM Try passing the word as a parameter to the render: <s:layout-render name="wrapped" word="${word}">
Hide
Ben Gunter added a comment - 10/Feb/12 8:05 AM

Nevermind, that doesn't work.

Show
Ben Gunter added a comment - 10/Feb/12 8:05 AM Nevermind, that doesn't work.
Hide
Peter Mahoney added a comment - 10/Feb/12 8:09 AM

Actually changing it to this does work:

<c:forEach var="word" items="${actionBean.words}">
<s:layout-render name="wrapper.jsp" wrapped="${word}" />
</c:forEach>

but obviously, that method is fairly limiting.

Show
Peter Mahoney added a comment - 10/Feb/12 8:09 AM Actually changing it to this does work: <c:forEach var="word" items="${actionBean.words}"> <s:layout-render name="wrapper.jsp" wrapped="${word}" /> </c:forEach> but obviously, that method is fairly limiting.
Hide
Ben Gunter added a comment - 10/Feb/12 8:11 AM

I think the best thing to do at this point – now that the things I really feel were flaws are fixed – is recognize that there are going to be limitations with the layout tags, and they aren't going to be 100% compatible with the old ones. As noted elsewhere, I'm not going to revert to the old, buffered code because there are too many advantages to the new, streaming code.

The best thing to do when you encounter something like this is to think about other ways to do what you're trying to do. Failing that, the buffered layout tags will be available in Stripes 1.5.7 by using an alternate taglib URI: http://stripes.sourceforge.net/stripes-buffered-layout.tld

Show
Ben Gunter added a comment - 10/Feb/12 8:11 AM I think the best thing to do at this point – now that the things I really feel were flaws are fixed – is recognize that there are going to be limitations with the layout tags, and they aren't going to be 100% compatible with the old ones. As noted elsewhere, I'm not going to revert to the old, buffered code because there are too many advantages to the new, streaming code. The best thing to do when you encounter something like this is to think about other ways to do what you're trying to do. Failing that, the buffered layout tags will be available in Stripes 1.5.7 by using an alternate taglib URI: http://stripes.sourceforge.net/stripes-buffered-layout.tld
Hide
Ben Gunter added a comment - 10/Feb/12 8:22 AM

After poking around a bit looking at this particular problem (the "dog" one) I've figured out what causes it, and I don't think there is a good way to fix it, given how streaming layouts operate. Without going into too much detail, I'll just offer this bit of advice: don't put layout-component tags inside loops. Instead, you can put a layout-render tag inside the loop and pass parameters to it, like you did above.

Show
Ben Gunter added a comment - 10/Feb/12 8:22 AM After poking around a bit looking at this particular problem (the "dog" one) I've figured out what causes it, and I don't think there is a good way to fix it, given how streaming layouts operate. Without going into too much detail, I'll just offer this bit of advice: don't put layout-component tags inside loops. Instead, you can put a layout-render tag inside the loop and pass parameters to it, like you did above.
Hide
Peter Mahoney added a comment - 10/Feb/12 8:30 AM

One of the great things about Stripes was the way that things "just worked". It is a shame there is no good solution to this problem, but I understand that there are major benefits to the change - particularly as Stripes memory issues caused our servers to go down last year. It is useful to know that now is the point to start changing our code to be compatible. Thank you for your help.

Show
Peter Mahoney added a comment - 10/Feb/12 8:30 AM One of the great things about Stripes was the way that things "just worked". It is a shame there is no good solution to this problem, but I understand that there are major benefits to the change - particularly as Stripes memory issues caused our servers to go down last year. It is useful to know that now is the point to start changing our code to be compatible. Thank you for your help.
Hide
Haggi added a comment - 14/Feb/12 2:42 AM

We have similar problems with the new streaming code solution of the layout renderer while using Freemarker as template engine. We revert to use the old layout renderer solution and everything works fine. What are the advantages of the streaming solution of the new layout renderer.

Show
Haggi added a comment - 14/Feb/12 2:42 AM We have similar problems with the new streaming code solution of the layout renderer while using Freemarker as template engine. We revert to use the old layout renderer solution and everything works fine. What are the advantages of the streaming solution of the new layout renderer.
Hide
Ben Gunter added a comment - 05/Mar/12 10:32 AM

Peter, I just committed a fix for STS-871. You might want to see if that helps your situation any.

Haggi, I have looked a little into the Freemarker thing, and I remember it being a Freemarker problem.

Show
Ben Gunter added a comment - 05/Mar/12 10:32 AM Peter, I just committed a fix for STS-871. You might want to see if that helps your situation any. Haggi, I have looked a little into the Freemarker thing, and I remember it being a Freemarker problem.
Hide
Peter Mahoney added a comment - 07/Mar/12 10:05 AM

Yes, the problem is fixed. Thanks. It also fixed a problem with two layout-renders with the same name ouputting the same content.

Show
Peter Mahoney added a comment - 07/Mar/12 10:05 AM Yes, the problem is fixed. Thanks. It also fixed a problem with two layout-renders with the same name ouputting the same content.
Hide
Ben Gunter added a comment - 07/Mar/12 10:07 AM

Excellent! So glad to know it. Thanks for all the testing.

Show
Ben Gunter added a comment - 07/Mar/12 10:07 AM Excellent! So glad to know it. Thanks for all the testing.
Hide
Peter Mahoney added a comment - 28/Mar/12 6:18 AM

I have come across a new problem with expressions being evaluated multiple times:

<c:set var="words" value="${actionBean.words}" />

<s:layout-render name="wrapper.jsp">
<s:layout-component name="first">
FIRST
</s:layout-component>
<s:layout-component name="second">
SECOND
</s:layout-component>
</s:layout-render>

wrapper.jsp:
<s:layout-definition>
<s:layout-component name="first" />
<s:layout-component name="second" />
</s:layout-definition>

actionBean.words will be evaluated three times - once correctly and the once per layout-component definition, which is strange. Obviously this is bad, because one of the main reasons for using the <c:set> is to avoid duplicate expensive calls.

Show
Peter Mahoney added a comment - 28/Mar/12 6:18 AM I have come across a new problem with expressions being evaluated multiple times: <c:set var="words" value="${actionBean.words}" /> <s:layout-render name="wrapper.jsp"> <s:layout-component name="first"> FIRST </s:layout-component> <s:layout-component name="second"> SECOND </s:layout-component> </s:layout-render> wrapper.jsp: <s:layout-definition> <s:layout-component name="first" /> <s:layout-component name="second" /> </s:layout-definition> actionBean.words will be evaluated three times - once correctly and the once per layout-component definition, which is strange. Obviously this is bad, because one of the main reasons for using the <c:set> is to avoid duplicate expensive calls.

People

Vote (0)
Watch (0)

Dates

  • Created:
    07/Mar/11 5:16 AM
    Updated:
    28/Mar/12 6:18 AM
    Resolved:
    22/Apr/11 2:32 PM