Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-9303

Portlet annotation handler mapping does is not working properly because of a flaw in predicate comparison



    • Type: Bug
    • Status: Closed
    • Priority: Minor
    • Resolution: Complete
    • Affects Version/s: 3.1.1, 3.1.2
    • Fix Version/s: 3.1.3, 3.2 M2
    • Component/s: Web
    • Labels:
    • Last commented by a User:



      Class org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping is using PortletMappingPredicate}}s. These predicates are used to compare priorities of different mapping (e.g. mapping with attributes has a higher precedence than the one without parameters) as they support {{java.lang.Comparable interface. When selecting appropriate handler AbstractMapBasedHandlerMapping#getHandlerInternal is sorting the predicates (Collections.sort).

      Example Implementation

      I can have handler class as follows:

      public class Foo {
          public String renderBar() {
              // ...
          public void processXyz() {
              // ...
          public String renderBaz() {
              // ...

      If I make request with parameter page=baz, the #renderBaz() method should be invoked. This might or might not happen (explanation bellow).

      Predicate Comparison

      Registering the example handler above (in DefaultAnnotationHandlerMapping) will result in creating three handler mapping predicates:

      1. RenderMappingPredicate for renderBar without parameters
      2. ActionMappingPredicate for processXyz without parameters
      3. RenderMappingPredicate for renderBaz with parameters

      Now what happens in AbstractMapBasedHandlerMapping#getHandlerInternal is that the list with these predicates gets sorted and the first one matching the request is picked. The problem is that when they have exactly this order they are not sorted at all.

      Comparison In Detail

      This is compareTo() method implementation from RenderMappingPredicate:

      public int compareTo(Object other) {
          if (other instanceof TypeLevelMappingPredicate) {
              return 1;
          else if (other instanceof RenderMappingPredicate) {
              RenderMappingPredicate otherRender = (RenderMappingPredicate) other;
              boolean hasWindowState = "".equals(this.windowState);
              boolean otherHasWindowState = "".equals(otherRender.windowState);
              if (hasWindowState != otherHasWindowState) {
                  return (hasWindowState ? -1 : 1);
              else {
                  return new Integer(otherRender.params.length).compareTo(this.params.length);
          return (other instanceof SpecialRequestTypePredicate ? 0 : -1);

      The code in ActionMappingPredicate is almost identical. If you check this code against the predicates from the example you will get following comparisons:

      • predicates[0].compareTo(predicates[1]) = 0 (1st RenderMappingPredicate vs ActionMappingPredicate)
      • predicates[1].compareTo(predicates[2]) = 0 (ActionMappingPredicate vs 2nd RenderMappingPredicate)

      The problem this issue is about is:

      • predicates[0].compareTo(predicates[2]) = 1 (1st RenderMappingPredicate vs 2nd RenderMappingPredicate)

      Where Is The Issue?

      The issue in comparison implementation is simple - parameter length should be compared first, regardles of the predicate type (you can see that the current implementation compares parameter length only in case predicates are of the same type).


          Issue Links



              juergen.hoeller Juergen Hoeller
              pavel.horal Pavel Horal
              Last updater:
              Spring Issues
              0 Vote for this issue
              2 Start watching this issue


                Days since last comment:
                2 years, 40 weeks, 2 days ago