Showing posts with label annotations. Show all posts
Showing posts with label annotations. Show all posts

Thursday, July 19, 2012

Order of Annotated Controllers When Matching @RenderMapping and @ActionMapping

ConfigurationJDK 7, Spring 3.1.1.RELEASE and Hibernate 4.1.3.Final. Multiple annotated controllers.

When you invoke a Render or Action mapping, it might happen the default mapping is picked up instead of the correct one.
This happens when the controller with the default mapping is first in the list.

DEBUG [http-8080-1] (AbstractMapBasedHandlerMapping.java:74) - Key [view] -> handler [{org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping$RenderMappingPredicate@2e19e=my.package.controller.DefaultController@12a8bad, ...

It's probably a bug or I don't understand the purpose yet.
This can be fixed by forcing Spring to put the controller with the default mapping last. First you scan all others and separately the default one:

    <context:component-scan base-package="it.italiangrid.liferay.doclibadmin.controller" use-default-filters="true">
        <context:exclude-filter type="regex" expression="EmiDocumentController"/>
    </context:component-scan>
    
    <context:component-scan base-package="it.italiangrid.liferay.doclibadmin.controller" use-default-filters="true">
        <context:include-filter type="regex" expression="EmiDocumentController"/>
    </context:component-scan>

Update I found out that if you use @RequestMapping instead of @RenderMapping and @ActionMapping in all methods of the controller with the default action, the problem seems to disappear.
You can use render and action mapping annotations in all other controllers.

References

Thursday, September 09, 2010

Spring Open View In Session Pattern For Portlets

I needed to implement the Open Session In View pattern for a portlet using Spring (3 with annotations) and Hibernate.
This pattern allows lazily loaded objects to have access to the Hibernate Session for the entire processing of the render request despite the original transaction (associated to the portlet request) already being completed.
I.e. If you have One To Many associations, this allows you to load the Many side of the association in the same thread of the request where you loaded the One side.

What I needed to do is:
Add a WebRequestHandlerInterceptorAdapter interceptor wrapping the stantard OpenSessionInViewInterceptor to applicationContext.xml:

<bean name="openSessionInViewInterceptor"
class="org.springframework.web.portlet.handler.WebRequestHandlerInterceptorAdapter">
<constructor-arg>
<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</constructor-arg>
</bean>

then add it to the DefaultAnnotationHandlerMapping in yourPortlet-portlet.xml:

<bean id="annotationMapper"
class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="10" />
<property name="interceptors">
<list>
<ref bean="openSessionInViewInterceptor"/>
</list>
</property>
</bean>