Getting stereotyped 'POJOs' by introducing the spring-mvc @Controller
annotation
When looking through the Pebble Model and Controller code I recalled a meeting taking place six months ago. I was told: 'Hey, you know how to use Spring in in the backend. But there is no solid knowledge in a frontend szenario'.
This scentence in mind a few week ago I decided to replace the legacy? Model
and View
classes with spring-mvc to gain some experience. Let's start with a look at the original ViewHomePageAction
:
import net.sourceforge.pebble.web.view.ForwardView;
import net.sourceforge.pebble.web.view.View;
import net.sourceforge.pebble.domain.AbstractBlog;
import net.sourceforge.pebble.domain.Blog;
import net.sourceforge.pebble.Constants;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ViewHomePageAction extends Action {
public View process(HttpServletRequest request, HttpServletResponse response) throws ServletException {
...
We've got two imports to the pebble View
implementation and three javax.servlet
imports. The stereotyped @Controller
action has neither of those imports. Beside the expected @Controller
we spot the spring 2.5 style RequestMapping
. The method is parameterless, a name matching the URL
and no checked ServletException
any more.
import net.sourceforge.pebble.model.Blog;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ViewHomePageAction {
@RequestMapping("/viewHomePage.action")
public String viewHomePage() {
The original method body:
AbstractBlog abstractBlog = (AbstractBlog)getModel().get(Constants.BLOG_KEY);
if (abstractBlog instanceof Blog) {
Blog blog = (Blog)abstractBlog;
String homePage = blog.getHomePage();
if (homePage != null && !homePage.equals("")) {
return new ForwardView("/viewStaticPage.action?name=" + homePage);
}
}
return new ForwardView("/viewBlogEntriesByPage.action?page=1");
is reduced to: 'If the blog has a valid homepage configured redirect to this homepage, view recent blog entries otherwise'.
String homePage = blog.getHomePage();
if (homePage != null && !homePage.isEmpty()) {
return "redirect:/viewStaticPage.action?name=" + homePage;
}
return "redirect:/viewBlogEntriesByPage.action?page=1";
There is no magic: I believe in the 'The Law of Conservation of Code Energy'.
Where has the code gone? It turned into XML
, a lot of XML
...
<bean id="blog" class="net.sourceforge.pebble.domain.SingleBlog" scope="blog">
<aop:scoped-proxy/>
</bean>
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="blog">
<bean class="net.sourceforge.pebble.scope.BlogScope">
<constructor-arg ref="blogManager" />
</bean>
</entry>
</map>
</property>
</bean>
Additionally there is a (http://static.springsource.org/spring/docs/2.5.6/reference/beans.html#beans-factory-scopes-custom">custom spring scope to support multiple blogs. In a first proove-of-concept I added a public
ThreadLocal
to the existing BlogLookupFilter
to have the blogId available in the current Thread
.
public static ThreadLocal<String> blogId = new ThreadLocal<String>();
And implemented the Scope
:
public class BlogScope implements Scope {
private final BlogManager blogManager;
public BlogScope(final BlogManager blogManager) {
this.blogManager = blogManager;
}
@Override
public Object get(String arg0, ObjectFactory factory) {
return blogManager.getBlog(BlogLookupFilter.blogId.get());
}
Wow, a lot of code and XML
. This added complexity to the software...Why do I still believe this is the way to go? There are about 100 action classes. All of them can be cleaned from javax.servlet
dependencies. This will remove more than 500 lines from the codebase. Testing is much easier and the code is more readable.
Today I removed the Pebble Model
and View
classes...in the next couple of days I will get rid of the javax.servlet
imports left in the action classes.