The Law of Conservation of Code Energy

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.