Wicket
  1. Wicket
  2. WICKET-5232

ComponentRenderer.renderComponent could accept components with any markupId, not just "compId"

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 6.8.0
    • Fix Version/s: 6.9.0, 7.0.0-M1
    • Component/s: wicket
    • Labels:
      None

      Description

      If you pass an existing component that has an arbitrary markupId to ComponentRenderer.renderComponent, it will fail:

      org.apache.wicket.markup.MarkupNotFoundException: Markup not found for Component: [Component id = myComponentId]

      This is because RenderPage markup uses a constant COMP_ID for the markupId:

      private static final String MARKUP = "<wicket:container wicket:id='" + COMP_ID + "'></wicket:container>";

      It would be nice if the ComponentRenderer would use the markupId of the given component.

        Activity

        Edvard Fonsell created issue -
        Hide
        Edvard Fonsell added a comment -

        I was able to make it work for me with these modifications to ComponentRenderer:

        1. Store the original parent of the component before rendering
        2. Pass the component ID to the RenderPage constructor
        3. Add the component back to the original parent after rendering (otherwise the component tree of the original page will be broken)
        4. Use the given component ID in RenderPage to generate the markup
        5. Disable caching of the RenderPage markup (otherwise next call to renderComponent with a different component ID will fail)

        public static CharSequence renderComponent(final Component component) {
        RequestCycle requestCycle = RequestCycle.get();
        final Response originalResponse = requestCycle.getResponse();
        final MarkupContainer originalMarkupContainer = component.getParent();
        BufferedWebResponse tempResponse = new BufferedWebResponse(null);
        try

        { requestCycle.setResponse(tempResponse); RenderPage page = new RenderPage(component.getId()); page.add(component); component.render(); }

        finally

        { requestCycle.setResponse(originalResponse); originalMarkupContainer.add(component); }

        return tempResponse.getText();
        }

        private static class RenderPage extends WebPage implements IMarkupResourceStreamProvider, IMarkupCacheKeyProvider {
        private static final long serialVersionUID = 1L;
        private static final String MARKUP = "<wicket:container wicket:id=\"%s\"></wicket:container>";
        private final String componentId;

        public RenderPage(final String componentId)

        { this.componentId = componentId; }

        @Override
        public IResourceStream getMarkupResourceStream(final MarkupContainer container, final Class<?> containerClass)

        { return new StringResourceStream(String.format(MARKUP, componentId)); }

        @Override
        public String getCacheKey(final MarkupContainer container, final Class<?> containerClass)

        { return null; }

        }

        Show
        Edvard Fonsell added a comment - I was able to make it work for me with these modifications to ComponentRenderer: 1. Store the original parent of the component before rendering 2. Pass the component ID to the RenderPage constructor 3. Add the component back to the original parent after rendering (otherwise the component tree of the original page will be broken) 4. Use the given component ID in RenderPage to generate the markup 5. Disable caching of the RenderPage markup (otherwise next call to renderComponent with a different component ID will fail) public static CharSequence renderComponent(final Component component) { RequestCycle requestCycle = RequestCycle.get(); final Response originalResponse = requestCycle.getResponse(); final MarkupContainer originalMarkupContainer = component.getParent(); BufferedWebResponse tempResponse = new BufferedWebResponse(null); try { requestCycle.setResponse(tempResponse); RenderPage page = new RenderPage(component.getId()); page.add(component); component.render(); } finally { requestCycle.setResponse(originalResponse); originalMarkupContainer.add(component); } return tempResponse.getText(); } private static class RenderPage extends WebPage implements IMarkupResourceStreamProvider, IMarkupCacheKeyProvider { private static final long serialVersionUID = 1L; private static final String MARKUP = "<wicket:container wicket:id=\"%s\"></wicket:container>"; private final String componentId; public RenderPage(final String componentId) { this.componentId = componentId; } @Override public IResourceStream getMarkupResourceStream(final MarkupContainer container, final Class<?> containerClass) { return new StringResourceStream(String.format(MARKUP, componentId)); } @Override public String getCacheKey(final MarkupContainer container, final Class<?> containerClass) { return null; } }
        Martin Grigorov made changes -
        Field Original Value New Value
        Status Open [ 1 ] Resolved [ 5 ]
        Assignee Martin Grigorov [ mgrigorov ]
        Fix Version/s 6.9.0 [ 12324357 ]
        Fix Version/s 7.0.0 [ 12322958 ]
        Resolution Fixed [ 1 ]
        Hide
        Edvard Fonsell added a comment -

        I'm sorry I was not able to test this fix before 6.9.0 was released, but it seems like it's still not working because step 5 (Disable caching of the RenderPage markup) of my suggested fix was not implemented. Is there some reason why the RenderPage should not implement IMarkupCacheKeyProvider and return null in #getCacheKey? Now calling #renderComponent with two components with different component IDs will fail on the second component because the markup including the first component's ID is cached.

        Show
        Edvard Fonsell added a comment - I'm sorry I was not able to test this fix before 6.9.0 was released, but it seems like it's still not working because step 5 (Disable caching of the RenderPage markup) of my suggested fix was not implemented. Is there some reason why the RenderPage should not implement IMarkupCacheKeyProvider and return null in #getCacheKey? Now calling #renderComponent with two components with different component IDs will fail on the second component because the markup including the first component's ID is cached.
        Hide
        Martin Grigorov added a comment -

        Create a new ticket please.

        Show
        Martin Grigorov added a comment - Create a new ticket please.
        Transition Time In Source Status Execution Times Last Executer Last Execution Date
        Open Open Resolved Resolved
        1h 58m 1 Martin Grigorov 13/Jun/13 09:04

          People

          • Assignee:
            Martin Grigorov
            Reporter:
            Edvard Fonsell
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development