Is this a Bug in Spring 3.1.2 ( specifically Sprin

2019-01-27 05:36发布

问题:

Background: I am developing a Portlet using Spring MVC framework deployed in liferay 5.x server. Currently I am using 3.0.0.RELEASE. Everything is working fine as expected. That is, when I use annotations like @RenderMapping(params="myaction=editFolderForm") @RenderMapping(params="myaction=editEntryForm") @RenderMapping
@ActionMapping(params="myaction=editEntry") etc. DefaultAnnotationHandlerMapping is working as expected in finding a handler for every request.

But, for some valid reason, I have to use more latest version which is 3.1.2.RELEASE instead of 3.0.0.RELEASE.

I observed that DefaultAnnotationHandlerMapping IS NOT WORKING as expected in finding a handler for every request. I figured out what is the problem by debugging the internals of Spring framework. I want to explain it clearly so that someone can tell me if this is a Bug.

In the parent class of DefaultAnnotationHandlerMapping which is AbstractMapBasedHandlerMapping :

package org.springframework.web.portlet.handler;
public abstract class AbstractMapBasedHandlerMapping<K> extends AbstractHandlerMapping {
....
.... 

/**
* Determines a handler for the computed lookup key for the given request.
* @see #getLookupKey
*/
@Override
@SuppressWarnings("unchecked")
protected Object getHandlerInternal(PortletRequest request) throws Exception {
   ...
   if (handler instanceof Map) {
     Map<PortletRequestMappingPredicate, Object> predicateMap =
                (Map<PortletRequestMappingPredicate, Object>) handler;
 List<PortletRequestMappingPredicate> predicates =
     new LinkedList<PortletRequestMappingPredicate>(predicateMap.keySet());

    LINE 81:    Collections.sort(predicates); ///////////////// PROBLEM


 for (PortletRequestMappingPredicate predicate : predicates) {
    if (predicate.match(request)) {
                predicate.validate(request);
                return predicateMap.get(predicate);
            }
        }
        return null;
    }
    return handler;
}
....
....
}

This sorting is screwed up in Spring 3.1.2 and is working perfectly well in Spring 3.0.0. In next two sections I ll tell you why sorting matters and how it is screwed up in Spring 3.1.2.

why sorting matters ?

This HandlerMapping is searching a sorted linked list node by node till it finds match for a particular handler. In my code base, I have multiple Controllers whose methods are mapped with following annotations like

@RenderMapping --- > default

@RenderMapping(params="myaction=editEntryController")

@RenderMapping(params="myaction=editFolderController")

etc.

The Collections.sort() depends on compareTo(..) method of each XXXPredicate class.

when a request comes first it should be checked if myaction parameter is equal to "editEntryController", "editFolderController", ...and finally if nothing matches, thn only default controller which is annotated with @RenderMapping annotation should be matched.

With Spring 3.0.0, its working exactly like that as expected. Where as wth Spring 3.2.1, its not behaving like that.

With both the versions, before sorting, the list is the same.

myaction=editEntry, 
myaction=editEntryForm, 
org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping$ResourceMappingPredicate@123bea8a,
myaction=REDIRECT_TO_DEFAULT_PAGE, 
 ,      ---------------------------------> This empty string corrsponds to the default @RenderMapping
 myaction=selectFolderEntries, 
 myaction=searchResults, 
 myaction=addEntry, 
 myaction=addEntryForm, 
 myaction=showMyEntries, 
 myaction=showRecentEntries, 
 org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping$ResourceMappingPredicate@4f1e9e2d, 
 myaction=editFolder, 
 myaction=editFolderForm,
 myaction=addFolder, 
 myaction=addFolderForm

After sorting,

With Spring 3.0.0,

org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping$ResourceMappingPredicate@123bea8a, 
org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping$ResourceMappingPredicate@4f1e9e2d, 
myaction=editEntry, 
myaction=editEntryForm, 
myaction=REDIRECT_TO_DEFAULT_PAGE, 
myaction=selectFolderEntries, 
myaction=searchResults, 
myaction=addEntry, 
myaction=addEntryForm, 
myaction=showMyEntries, 
myaction=showRecentEntries, 
myaction=editFolder, 
myaction=editFolderForm, 
myaction=addFolder, 
myaction=addFolderForm,
             ---------------> Default mapping i.e. @RenderMapping

With Spring 3.1.2 ( ignore things like [ ] ),

[myaction=editEntry]
[myaction=editEntryForm]
deleteFolder
[myaction=REDIRECT_TO_DEFAULT_PAGE]
[]        --------------------------> this is wrongly placed in middle.
[myaction=selectFolderEntries]
[myaction=searchResults]
[myaction=addEntry]
[myaction=addEntryForm]
[myaction=showMyEntries]
[myaction=showRecentEntries]
deleteEntry
[myaction=editFolder]
[myaction=editFolderForm]
[myaction=addFolder]
[myaction=addFolderForm]
null

This is a linked list. And each mapping is checked from the first node. When ever the default [] i.e. an empty mapping is found in the middle of the list, true is being returned as if that is the right handler and rest of the handlers are not checked.

So is this a bug in Spring framework 3.2.1 ?

回答1:

I had the same problem. Only version 3.1.4 was working for me.