Lessons Learned in Java Web Development

Designing web interfaces to achieve maintainable and extensible apps requires discipline. The best motivation for achieving this discipline is awareness of the consequences of failing to achieve it. The following brief discussion of the history of Java web development serves to illustrate the dangers that we must avoid.

The Shortcomings of Servlet-only Solutions

The first Java web technology was servlets. The first release of the Servlet API back in 1997 was an improvement on the dominant existing technology, the primitive Common Gateway Interface (CGI) standard for server-side script invocation. Instead of scripts written in languages such as C or Perl, which usually caused a new process to be created to handle each request, servlets allowed dynamic content to be generated by reusable Java objects. Servlets had full access to the power of the Java language, including JDBC and the Java object model, and so elevated web development to true OO development. At least in theory - the Servlet specification was a big step forward, but developers soon ran into problems building real apps. Servlets proved very good at invoking business objects. However, generating complex markup from Java code is awkward. If markup strings are embedded in servlet and helper classes, changes to the presentation of web content always require modification of Java code and recompilation; Java developers must always be involved. Furthermore, it can be very difficult to see how a complete page is assembled from markup littered throughout Java objects, making sites very difficult to maintain. Servlets proved much more effective at generating binary content. However, this is a rarer requirement.


Generating markup from Java objects such as servlets is clumsy and leads to unmaintainable web apps. The servlet specification alone is not enough to meet the challenges of most web apps.

It was clear that additional infrastructure was needed. Many developers used templating approaches, in which markup was held outside Java code, with servlets responsible for generating only the dynamic content. However, there was no widely adopted standard.

JSP: Promise and Temptation

Thus the release of the JSP 0.92 specification in 1998 created widespread excitement. JSP was a standard templating solution, endorsed by Sun. Although JSP pages are transparently compiled into servlets by a web container, JSP pages use a very different approach from servlets. While servlets are Java objects capable of generating markup, JSP pages are markup components that permit escaping into Java as necessary to initiate processing. JSP was soon in wide use, and overenthusiastic adoption led to a host of new problems. Experience quickly demonstrated that a model based on escaping into Java as necessary to generate dynamic content was a new evil in place of the old need to generate markup from Java code. The release of JSP 1.0 in 1999 was a significant improvement on JSP 0.92, but did not change the underlying model or address these problems.

"JSP Model 1" Architecture

To understand these problems, let's consider the simplest and most obvious architecture for a J2EE web app's interface. Imagine that we use JSP pages to implement the entire web interface. Each JSP handles incoming requests, creating domain objects from request parameters and using them to invoke business objects. Each JSP then renders the result of the business processing. The JSP infrastructure makes it easy to implement this approach, using JSP pages with a mix of markup and embedded Java code. The standard JSP infrastructure allows JSP pages:

This kind of web app architecture is often termed the JSP Model 1 architecture. Core J2EE Patterns uses the more meaningful, but rather overblown, term, Physical Resource Mapping Strategy. I'll use the older term, JSP Model 1, in this chapter. This approach is simple to implement. All we need to do is write the JSP pages and provide the support classes. There is no need to write servlets or define URL-to-servlet mappings in the web.xml deployment descriptor. Development-deployment cycles are often short, as JSP pages can be recompiled automatically by the web container as they are modified. However, this approach mostly produces very poor results in practice. apps built using this approach (and far too many are, even today), face the following severe problems:


The JSP Model 1 architecture, in which JSP pages handle incoming requests, results in non-maintainable apps. JSP Model 1 should never be used in real apps: its only use is in prototyping.

The Temptation of the JSP Standard Infrastructure

Hopefully you're already convinced that JSP pages are not the ultimate answer to J2EE web interfaces. In case you aren't, let's consider some of the shortcomings of the JSP standard infrastructure, which makes it easy to attempt many things that subvert good design, and makes the JSP Model 1 architecture plausible on first impression. Request parameters can be mapped onto JSP beans in two ways. Individual request parameters can be mapped onto a bean property using a <jsp:setProperty> action like this:

 <jsp:setProperty property="propertyName" param="paramName" />

Alternatively, all request properties can be mapped onto a bean in a single <jsp:setProperty> action like this:

 <jsp:setProperty property="*" />

The JSP mechanism for mapping request parameters onto bean properties is an unrealistically naÏve approach to data binding (a problem we'll discuss in detail later). Problems include the following:

We'll end up needing to write our own request handling code in the JSP to address these shortcomings, which defeats the purpose of the property mapping infrastructure.


The standard JSP infrastructure for mapping request parameters onto JSP beans is primitive and next to useless in real apps.

Another tempting feature of the JSP standard architecture, which encourages Model 1 architectures, but shouldn't be used in real apps, is the ability to define methods and even classes in JSP pages. Normally code in scriptlets ends up in the JSP's_jspService() method. By using <%! syntax instead of <% we can ensure that embedded Java code goes outside this method, defining methods, variables, and classes in the generated class itself.

JSP is very powerful, but its powerful, but its power creates as much danger as benefit. JSP lets us do anything we might legitimately want to do in a view, and a lot of things that we're best not to attempt. Since its initial release, JSP has gained new capabilities: most significantly, the addition of custom tags, which enable Java helper code to be concealed behind markup. However, the basic model hasn't changed, and nor has the fact that JSP pages are excellent at displaying data, and ill-suited to request processing and initiating business logic.

Striking a Balance

Both the approaches discussed so far – servlet-only and JSP Model 1 – have severe disadvantages and make it impossible to achieve separation of responsibility between Java developer and markup developer roles. Such separation is essential on complex web sites. However, by using the two technologies together – servlets to handle control flow, and JSP pages or another view technology to render content – we can avoid the problems I've described. A so-called JSP Model 2 architecture introduces a controller servlet as the central entry point, rather than individual JSP pages. The controller is responsible for request processing, and chooses a JSP to render content depending on request parameters and the result of the necessary business operations. In fact, as we'll see, there are many refinements to this model: it's important to avoid having a single "God" servlet, but ensure that the servlet works with a number of sub-controllers. I won't refer to this as JSP Model 2 architecture, as in fact this architecture isn't dependent on JSP: it works with any templating technology. Its basis is servlets - by far the more important of J2EE web technologies. I'll use the term Front Controller pattern, which is used by Core J2EE Patterns. This is an attempt to apply the MVC architectural pattern (which we'll discuss further below) to web apps. This pattern, which we'll discuss in detail below, is the key to designing maintainable J2EE web apps, and the central point of this chapter.


Both servlets and view technologies (such as JSP) are required for building maintainable J2EE web apps. Servlets and helper classes should be used to handle control flow and initiate business operations; JSP should only be used to render content.