Uploaded image for project: 'Wicket'
  1. Wicket
  2. WICKET-4570

Shared Behavior's renderHead method called only for one component, not for all of them

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Minor
    • Resolution: Fixed
    • 1.5.0, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.5.5, 1.5.6, 6.0.0-beta1
    • 1.5.8, 6.0.0-beta3
    • wicket
    • None

    Description

      When using a shared behavior among many components, its renderHead method is called only once. The reason is at the end of the Component.renderHead(HtmlHeaderContainer) method:

      for (Behavior behavior : getBehaviors())
      {
      if (isBehaviorAccepted(behavior))
      {
      if (response.wasRendered(behavior) == false) // <---- check whether the behavior has been marked as rendered

      { behavior.renderHead(this, response); response.markRendered(behavior); // <---- behavior marked as rendered }

      }
      }

      When calling this method of the first component, which contains given Behavior, the Behavior is added to the set of the already-rendered elements. This means, its renderHead method is never called for the rest of the components, which contain it.

      From documentation I suggest:

      • Behaviors can be shared among more components (if they are not "attached" in bind() method), as written in Behavior class javadoc: "They can be bound to a concrete component (...), but they don't need to."
      • A Behavior method should behave the same way, as the same code placed directly in the component (in the corresponding method)

      Moreover, in the documentation of the Behavior.renderHead is written: "Render to the web response whatever the component wants to contribute to the head section." So as I understand it, the information about component should also be the "key" whether to mark the Behavior rendered or not. More precisely, the proposed solution should be something like the following (Couple means something like a class with two fields - Behavior and Component):

      for (Behavior behavior : getBehaviors())
      {
      if (isBehaviorAccepted(behavior))
      {
      Couple c = new Couple(behavior, this); // <---- create couple
      if (response.wasRendered(c) == false) // <---- check the couple

      { behavior.renderHead(this, response); response.markRendered(c); // <---- mark the couple as rendered }

      }
      }

      Maybe this is not a bug, but a feature. In case of the feature I think, that it requires at least a clarification in the documentation. In (probably) all other usage of shared Behavior, the Behavior does not cause any troubles and it behaves as expected from the documentation. But this method has quite inconsistent effect, comparing to the other ones.

      If an example is needed:

      I need a Behavior to attach all components, which have to automatically contribute to HTML head a JavaScript and CSS file with the same name as the component. The Behavior does not hold any data (no fields, empty bind method), so I would like to make it singleton (or not directly pattern Singleton as such - for example let it overridable, but provide a default instance). Because creating new instances does not have much sense in this case and it brings many unnecessary objects on the heap.

      Using of new instance per component works fine, of course, but the issue is in the situation, if I need the shared instance across the application.

      Attachments

        Issue Links

          Activity

            People

              mgrigorov Martin Tzvetanov Grigorov
              otah Ota Hauptmann
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: