Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Your Next Java Web App: Less XML, No Long Restarts, Fewer Hassles (Part 1)

Note: This tutorial is gonna show you how to code Java without any of the traditional B.S., like XML and app server restarts. It’s split into 3 parts so that your brain doesn’t freak out at a 50 meter long webpage. Enjoy!

Part 1 | Part 2 | Part 3

———————————-
Did you realize that Hibernate has been around for more than 10 years? And Spring will begin its second decade next year? There was a time when Spring+Hibernate was widely considered an unofficial industry standard, but today is portrayed as an ancient beast whose XML appetite kills little rainbow scroll wheels. That assessment is not true, however. Both technologies have seen continuous development and are still competitive today.

Doesn’t it make more sense to compare apples to apples? For example, don’t put JEE6 with CDI up against Spring 1.0. Spring and Hibernate don’t require three miles of XML anymore. In fact, it’s possible to set them both up with zero lines of XML.

With servlet 3.0, even web.xml can go the way of the dodo. When all you’re trying to accomplish is a simple helloWorld guestbook, then Java, Spring and Hibernate will require more effort to get there, but can you name any app which is that trivial in real life? Proper applications are expected to satisfy far greater needs, both functional and non-functional, which is the area where Java, supported by wisely-chosen tools & frameworks, really shines.

Download the pdf



Why don’t we name some qualities of a modern web application? Let’s think about what we would like to see as the result, and work back from there. The app should:

  • Be simple and easy to set up, rivalling pure JEE6, Play! Framework, or ***-on-rails
  • Remain simple and easy when complexity gets beyond what is usually shown in tutorials
  • Be easy to run and test on a developer machine as well as on remote servers
  • Maximize developer productivity
  • Be flexible and robust enough to support a wide array of enterprise requirements (which will be completely different after your boss gets back from the lunch break)
  • Have a huge community and know-how behind it
  • Keep away from magic and be easy to debug

Java apps are never just about pure Java. It takes a combination of Java, frameworks and tools to get the most out of the platform.

The lineup

For this task, my arsenal includes the latest versions of Spring Framework 3.1 and Hibernate 4.1. I’m also using a tiny bit of BeanValidation to make the code sparkling. In addition to the frameworks, I have chosen some tools for developing the beast. One of the biggest benefits to productivity is having a Maven project which can be launched from within your IDE and updated on the fly with JRebel (Disclaimer: I joined ZeroTurnaround to work on the JRebel team in 2010).

Maven 3

I’m creating a maven project which can be built and deployed with one command on the remote server. On the developer side, it removes all the hassle of managing dependencies and troubleshooting errors when some library is missing.

http://maven.apache.org/download.html

Eclipse 3.7

I am personally used to Eclipse and will be using it in the article. Feel free to use IntelliJ IDEA or NetBeans instead. The important part is having the proper plugins that play well with Maven and JRebel. For Eclipse, these plugins are:

  • Maven integration (m2e)
  • Maven integration for WTP
  • JRebel for Eclipse

Maven Integration for WTP is a separate plugin from m2e and is essential for launching a maven project in a container from within Eclipse. You can install all of them from the Eclipse Marketplace.

http://www.eclipse.org/downloads/

JRebel 5.0

JRebel allows you to see all sorts of changes to Java code in your app instantly, and it includes changes to Spring bean definitions and Hibernate mappings. It removes what is perhaps the biggest weakness of Java when compared to Grails, PHP or the like – downtime during the build/compile/restart phases. Plus you get to keep all what’s great about Java.

JRebel Remoting, new to JRebel 5.0, allows you to upload changes to a remote machine and have the changes instantly reflected there too. It works with Jelastic, Rackspace and Amazon EC2 out of the box.

http://zeroturnaround.com/jrebel/current/
http://zeroturnaround.com/software/jrebel/remoting

Tomcat 7

IMHO, the app server you choose is probably the least important decision. Stick to what you feel most comfortable with. However, it should be as lightweight as possible. In the past it meant using only a servlet container instead of a full blown JEE server, but today there are several JEE Web Profile offerings which also start up pretty quickly.

I prefer Tomcat, but this can freely be substituted with alternatives (such as Jetty 8, JBoss 7 or Glassfish 3.1, which are all free and start up reasonably fast). Use any of those if you dislike Tomcat.

http://tomcat.apache.org

Creating the Project

I like to start by creating a blank Dynamic Web Project in Eclipse. I select “None” as a target runtime, “3.0“ as the module version and “minimal” under “Configuration”. That should result in a minimum possible setup for a servlet 3.0 application. Next I add Maven support to it. To do that, right-click on the newly created project and select Configure->Convert to Maven Project. Sometimes that messes up the Eclipse build and source directories. Make sure the src dirs of the project are src/main/java and src/main/resources, creating the folders when needed, and output dir should be target/classes.

Next you need to add a bunch of dependencies, like Spring and Hibernate, as well as Servlet API and a few more. Configuring the POM is the most boilerplate’ish part of the whole process, but it can actually be accomplished via GUI in Eclipse. Adding dependencies is easy. The biggest problem of Maven is that it’s nontrivial to make adjustments to the build process (such as changing the default Java version). In the end, I end up with the following POM. I have annotated the file with comments as to why one or the other bit of configuration is necessary.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <!--replace with your namespace and version -->
  <groupId>com.zt</groupId>
  <artifactId>helloWeb</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <!--should not be changed -->
  <packaging>war</packaging>

  <!--some custom options are necessary. Perhaps they make their way to a convention in the future -->
  <build>
    <plugins>

      <!--source level should be 1.6 (which is not Maven default) for java EE 6 projects, so let's change it -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>

      <!-- When using xml-less approach, you need to disable Maven's warning about missing web.xml -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>

    </plugins>
  </build>

  <dependencies>

    <!--We need servlet API for compiling the classes. Not needed in runtime -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>

    <!--adding spring mvc is easy -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>3.1.1.RELEASE</version>
    </dependency>

    <!-- Required for xml-less configuration of Spring via @Configuration annotations -->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib-nodep</artifactId>
      <version>2.2.2</version>
    </dependency>

    <!-- required for getting spring working with Hibernate -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>3.1.1.RELEASE</version>
    </dependency>

    <!-- Adding Hibernate -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>4.1.2</version>
    </dependency>

    <!-- Only needed when using JPA instead of "pure Hibernate" -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>4.1.2</version>
    </dependency>

    <!-- DB connection pooling for production applications -->
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>

    <!-- replace with concrete JDBC driver depending on your DB -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.19</version>
    </dependency>

    <!-- Add Taglib support -->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
      <!-- Use Provided when using JBoss or Glassfish, since they already bundle it. I'm using Tomcat so it has to go in -->
      <!-- <scope>provided</scope> -->
    </dependency>

  </dependencies>

</project>

All that’s left to do is changing the src directory to src/main/java and output folder to target/classes in Eclipse. You could also check whether paths are mapped correctly under Deployment Assembly. Note that you may have to refresh the project configuration after modifying the pom.xml. To do that, right click on the project and Maven->Update Dependencies.

Hello World, goodbye XML!

Servlet 3.0 introduces a ServletContainerInitializer interface whose implementing classes are notified by the container about webapp startup events. Spring 3.1 uses this in its WebApplicationInitializer interface, which is the hook through which you can set up ApplicationContext without using the web.xml. Combine that with Spring’s Java-based configuration, and you can successfully ditch XML files entirely.

First, you need to create a class that implements that Spring’s WebApplicationInitializer interface. Then create the application context programmatically and finally add the servlet to the ServletContext (again, programmatically). The resulting initializer class looks like this:

public class Initializer implements WebApplicationInitializer {
 
  // gets invoked automatically when application starts up
  public void onStartup(ServletContext servletContext) throws ServletException {
 
    // Create ApplicationContext. I'm using the
    // AnnotationConfigWebApplicationContext to avoid using beans xml files.
    AnnotationConfigWebApplicationContext ctx =
        new AnnotationConfigWebApplicationContext();
    ctx.register(WebappConfig.class);
 
    // Add the servlet mapping manually and make it initialize automatically
    Dynamic servlet =
        servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    servlet.addMapping("/");
    servlet.setLoadOnStartup(1);
  }
 
}

The trick that helps us get rid of applicationContext.xml files is achieved by using AnnotationConfigWebApplicationContext instead of XmlWebApplicationContext. I put the configuration in the WebappConfig class, which is annotated with @Configuration. All that is available in XML files can be done here programmatically. For example, adding @ComponentScan("com.zt.helloWeb") turns on Spring’s scanning for annotated beans, akin to the previous <context:component-scan> directive. WebMVC is enabled via @EnableWebMvc and PropertyPlaceholderConfigurer is replaced with @PropertySource("classpath:filename.properties"). Beans are declared via adding @Bean annotation to a method that produces the object. The name of the method is not important. I’m using this to configure a ViewResolver (see below). The whole simple configuration class looks like this:

@Configuration
@ComponentScan("com.zt.helloWeb")
@EnableWebMvc
public class WebappConfig {
 
  @Bean
  public InternalResourceViewResolver setupViewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/views/");
    resolver.setSuffix(".jsp");
 
    return resolver;
  }
 
}

All that’s left to do is adding a simple controller class, which maps to /hello and renders hello.jsp …

@Controller
public class FooController {
 
  @RequestMapping("/hello")
  public String helloWorld(Model model) {
    //let’s pass some variables to the view script
    model.addAttribute("wisdom", "Goodbye XML");
 
    return "hello"; // renders /WEB-INF/views/hello.jsp
  }
 
}

..and even smaller jsp file:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"%>
<html>
    <head>
        <title>This goes to top</title>
    </head>
    <body>
        <h1>Hello World, ${wisdom}!</h1>
    </body>
</html>

The final application source contains just 4 files + pom.xml:

-- pom.xml
-- src
   -- main
      |-- java
      |   -- com
      |      -- zt
      |         -- helloWeb
      |            -- controllers
      |         	   -- FooController.java
      |         	-- init
      |         	   -- Initializer.java
      |         	   -- WebappConfig.java
      |-- webapp
          -- WEB-INF
       	  -- views
       		 -- hello.jsp

This app can be easily launched from Eclipse and also built on a remote server using Maven. Try it, it’s a fully functional HelloWorld webapp!

Even though it is possible to set up the webapp without any XML files, I leave it up to you decide how big of an improvement this actually is. It’s certainly not a silver bullet. Also, app containers’ support for the new options is still buggy. For example, the webxml-less approach does not work on JBoss correctly. It is buggy on the 7.1.1 version and fails completely on 7.0.2. You might also not be always able to use servlet 3.0 capable servers in production.

For me, the most offensive part of XML is having to include a crapload of namespaces in Spring’s applicationContext.xml. For example, I never create that file from scratch and copy-paste it instead:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" >

Web.xml is far less verbose however and works even on JBoss. In the above setup, the class Initializer can be replaced by the following web.xml (we’ll still be using Spring’s javaconfig, and for compatibility’s sake I reduced the servlet version to 2.5):

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- we'll use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext... -->
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>

    <!-- ... and tell it which class contains the configuration -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.zt.helloWeb.init.WebappConfig</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>

  </servlet>

  <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>/</welcome-file>
  </welcome-file-list>

</web-app>

DefaultServletHandler

The caveat of mapping DispatcherServlet to “/” is that by default it breaks the ability to serve static resources like images and CSS files. To remedy this, I need to configure Spring MVC to enable defaultServletHandling.

To do that, my WebappConfig needs to extend WebMvcConfigurerAdapter and override the following method:

 @Override
  public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
  }

Continue to Part 2

Download the pdf




  • Sreenath V

    JEE 6 with CDI is the way to go…

    http://www.techiesinfo.com/

  • gelin luo

    I am a Play!Framework (1.x specifically) people. I got some feelings after reading your article. 1. Those 30 chars+ names in your code really scared me. 2. The servlet mapping is web.xml looks terrible compare to conf/routes of Play!Framework. 3. JRebel is not a free stuff. I would say this is not a rival of Play!Framework at all.

  • arhan

    Sure, not a rival at all. It is just so much more superior :)

  • Singh

    Arnel, you even aware of jsf,
    CDI and java bean? Spring is great for glue components together, but not for web application at all. Please have a look at
    http://www.mkyong.com/jsf2/jsf-2-0-ajax-hello-world-example/

  • SajDutt

    Pet controller should have removing functionality as well to make this project complete. Currently it’s mapped to addPet only. View pet should have a delete button that triggers the removal of the pet. And lastly users should be able to delete the pictures of the pets. Currently ‘x’ doesn’t work on pictures.
    But this is a fine tutorial for beginners.

  • http://twitter.com/Wlanez Wladimir Nunez

    I love JEE but we are paid to develop software and (I think) Play makes
    this work easier, it’s mean that is better for our business.

  • gelin luo

    it’s NOT superior just because of your words. show your proof and help us understand why

  • arhan

    1) Play! does not reload classes in libraries/dependencies
    2) Play! does not reinitialize metadata of any frameworks if you use them as dependencies, for instance Guice (because some people still want DI)
    3) As gossips say, with large code base Play reloading is getting much slower (and we have clients who asked JRebel support specifically for Play just for that reason).

    Play is very productive and we use play to build our webapps, so I’m not offended at all. My message is just that JRebel does it’s job at much more advanced level than any framework can do.

  • gelin luo

    First, I am not talking about JRebel here. When I say “rival” I mean the framework stacks (Play VS. the Servlet 3.0 based stack). JRebel is just one tool, or one component of the stack mentioned in this blog. Let’s say you can’t use JRebel ONLY to create a web application, so the words that “JRebel does it’s job at much more advanced level than any framework can do” makes nonsense to me.

    Second, JRebel is a commercial product, I am not surprised at all if it is superior than Play’s class reloading mechanism on certain aspect. The point is to what extend we would like to pay this extra advantage in a general project. What you mentioned in your arguments to me are more part of configuration management than a development issue.

    Play provides class reloading to application code because you change it every second while developing your project, but how often did you change your dependency jar libraries? I won’t pay a penny for library hot reloading because it’s not a feature I want. On the contrary I object to this feature. Doing that makes it too easy to break our configuration management.

    Large code base (which cause long delay in app class reloading) of one application should be avoid in the project (again this belongs to the configuration management). You should modularize your BIG apps by break them done into modules for the sake of complexity management. Any serious software engineering team should tackle complexity in a systematic way (SCM) instead of relying on a super tool like JRebel. Hot reloading is one feature for development convenience, over rely on it is just like you count on a compiler to detect all defects in your code.

  • arhan

    understood. thumbs up!

  • yevmel

    some people would spread their configuration over the the entire code just to avoid writing/reading xml… questioning the benefits would be heresy, right?

  • Oleksiy Rezchykov

    Thanks for the article. An App could look even more pretty and XML-less with Gradle instead of Maven.

  • donjuantonio

    Thx Arnel; great look into how to avoid XML, something I’ve detested about developing with frameworks over the last 8 years. Love to program in a programming language rather than tagged strings… imagine that. :)

  • purchaser craigslist

    web.xml comes up with easy error handling like for example: and
    How to go about replacing this feature with Annotations or in this case how would you configure with Initializer?

  • sk

    JRebel should stick to legacy apps (anything written in java) classloading as it is a great tool for that. JRebel is not required for PHP or Rails. Same applies for Play.
    there is always OSGI for library loading.

  • arhan

    Legacy apps are the bread&butter for JRebel. However, it doesn’t mean that the new technologies do not suffer from redeploys at all. They suffer much less. We’re getting requests to support frameworks like Play and Grails quite regularly. Once the application size grows up to certain size, redeploys still strike back sometimes. OSGi is a bit different in that aspect – library re-loading in OSGi is rather a nice side effect than a primary goal.

  • Robby

    found this tutorial really helpful but im still not sure how to view the hello.jsp page in my browser. I ran a maven install and started the server, but i only get 404 errors when trying to visit the page..

    the groupId I specify in the pom is com.musicshare and the artifactId is helloWorld

    What should come after localhost:8080 in the url i place in my browser?

  • Robby

    P.S. Ive basically copied exactly what you have for the first 4 source files, and I also added all the appropriate folders (WEB-INF, views, com) to match your folder structure

  • Patrick

    hello, i would thank you sir for the tutorial,
    explanation is great.
    when running app, typing “http://localhost:8080/helloweb/hello” gives me 404 ressource not found error.
    then in WebappConfig i changed from @ComponentScan(“com.zt.helloweb”)
    to @ComponentScan(“helloweb”)
    and then i was able to render the jsp.