When someone starts to make a path, most people tend to follow the trail. So when Sun introduced the Servlet API, most people were uneasy about the design problems:
- Servlets are singletons (which are evil; this is due to performance problems in Java 1.2 which have been fixed about ten years ago).
- The resulting code smells (feature envy since you call many methods of
HttpServletRequest/Response, long method since you can’t call subdivide thedoGet()without passing at least two parameters to each new method, duplicated code since you have to walk instance trees to get at a lot of information, …)
Whenever I see Java servlet code, I always wonder why people don’t solve this. It’s so simple:
public abstract class ServletRequestHandler {
protected HttpServlet servlet;
protected HttpServletRequest request;
protected HttpServletResponse response;
protected String contentType = "text/html";
public void init(
HttpServlet servlet,
HttpServletRequest request,
HttpServletResponse response
) {
this.servlet = servlet;
this.request = request;
this.response = response;
}
public abstract void process();
public PrintWriter out() {
if( null == out ) {
response.setContentType( contentType );
try {
out = response.getWriter();
} catch( IOException e ) {
throw new RuntimeException(
"Can't get writer", e
);
}
}
return out;
}
public ServletRequestHandler html( String html ) {
out().print( html );
return this;
}
public ServletRequestHandler attribute( String value ) {
out().print( escape( value ) );
return this;
}
public ServletRequestHandler attribute(
String name,
String value
) {
if( StringUtils.isBlank( value ) ) {
return this;
}
PrintWriter out = out();
out.print( ' ' );
out.print( name );
out.print( "=\"" );
out.print( escape( value ) );
out.print( "\"" );
return this;
}
public ServletRequestHandler text( String value ) {
out().print( escape( value ) );
return this;
}
// Add more methods to support your favorite
// web design patterns
}
Now, all your servlets look the same: They accept the request, create a new instance of the right implementation of ServletRequestHandler, and call init() plus process(). With a bit of glue code, you can even use Spring to manage all your servlets for you. No more dabbling with web.xml!
And the best part: This pattern allows you to test the servlet code from a unit test without any container. Just use Spring or Mockrunner to get mock-ups for the J2EE API classes.
Posted by digulla