Article Series: Migrating Spring Applications to Java EE 6 – Part 2

April 17, 2012

Developer Topics, Java EE

Bert Ertman  and Paul Bakker of Luminis have written a multi-part article that covers migrating Spring Applications to Java EE 6 technology.  It also consists of sample code a working project.  In the series Paul and Bert discuss the rationale for migrating your applications from Spring to Java EE 6 and show you real examples of upgrading the web UI, replacing the data access layer, migrating AOP to CDI interceptors, migrating JMX, how to deal with JDBC templates, and as an added bonus will demonstrate how to perform integration tests of you Java EE 6 application using Arquillian.

See the PDF here “Migrating Spring to Java EE 6 – Part 2″  or read online below.

PART 2 – Migration approach

In the first part of the series we introduced you to the idea of migrating your legacy Spring applications to Java EE 6. The design and framework choices that you made five or six years ago are increasingly adding up to the technical debt and maintenance burden of your current application. Since fixing these issues is a lot of work anyway, why not take it to the standard? In this article we will explain the migration steps that we came up with and show you how to apply them to a real world example application. This article contains a number of code examples and a reference to a project in GitHub that you can use as a reference.

Step 1 – Upgrade Spring to the latest version

The first thing you should do is simply upgrade the Spring version; update your Maven dependencies or replace the jar files. We will not change any code or configuration yet, so the upgrade to the latest Spring version doesn’t really improve the situation. It does give the flexibility to use some newer technologies such as JPA 2 within Spring however, and that’s what we need next. Upgrading Spring should be as easy as dropping in the new dependencies. Backwards compatibility in Spring is generally very good.

Step 2 – Replace old or out-dated frameworks within Spring

Most Spring applications are not just using Spring. Instead they use a whole bunch of frameworks and integrate them using Spring. A typical Spring application could look like figure 1.

Figure 1: A typical Spring application

In this case there are two obvious parts of the application that needs to be updated:

  1. The DAO framework (Kodo)
  2. Spring Web MVC

Kodo, and many other old ORM frameworks, are not maintained any more and are now obsolete due to the introduction of JPA. It’s also hard to find any developers for frameworks like this. Modern Spring applications also focus on using JPA and have good support for this. Spring Web MVC is replaced by an annotation based version of the framework. The old model is deprecated. Unfortunately it is not very trivial to migrate from the old model to the new model.

Because we need to take small steps to migrate a large code base to modern technology we start by replacing one of the outdated technologies within Spring. For example, you could replace Kodo by JPA 2 within Spring. Notice that we are using some Java EE technology now, but we don’t have to start using a Java EE application server yet.

At some point you will run into places where you either want to start developing new functionality or start using Java EE technology that is not supported by Spring.

Step 3 – Run Spring and Java EE side-by-side

When new functionality is developed it should use the new technology stack, while still integrating with existing code. For example, we start writing JSF/CDI code while still using our Spring JDBC templates for data access. If we look at the deployment model of both Spring and Java EE there is a clear difference. If you compare figures 2 and 3, you see that  Spring packages framework functionality within the application. Because of this you only need a Servlet container, but end up with huge WAR files. Java EE has all the framework functionality in the application server, so you don’t need to package it in your WARs. There is really no good reason to use a Servlet container instead of a real application server now days. Startup times are the same, so why bother with the complexity of managing a large amount of dependencies in your project and packaging them with each build? There are 14 Java EE application servers at the moment of writing, both for free and commercially supported.

Figure 2: packaging of a Spring application.

Figure 3: packaging of a Java EE application.

What we do to start using Java EE without loosing old code, is running the two container models side-by-side. To be more precise, the Spring container will run within the Java EE container as displayed in figure 4. We will use CDI to integrate both containers. The Spring container starts up as usual, but CDI will then make all Spring beans available to Java EE code using CDI injects. In the new code we can’t even see if injected beans are created by Java EE or Spring, so further migration will not force us to change any new code. How CDI and Spring are integrated is discussed on a more technical level further in the article.

Step 4 – Replace Spring entirely

We have been replacing Spring code for a while now, and there is not much left. Most work was in the migration of outdated frameworks. It will be a relatively minor task to remove the remaining Spring code too, because the programming models are now quite similar. There might still be challenges such as the use of Spring JDBC Templates. We will discuss this in depth in the following articles in this series.

Step 5 – Remove Spring

Now that there is no Spring code any more, we can also remove all it’s dependencies. For Java EE we don’t need to package any libraries with our application, so we can go from a whole list of dependencies to just one: The Java EE API.

Example application

The example application is a modified version of the Spring Pet Clinic. The original pet clinic has multiple implementations of the data access layer to explain the integration with different ORM solutions. Because this is not relevant for this article series we stripped out the Hibernate, Toplink and JDBC implementations which leaves us with JPA. The application is already implemented using the latest Spring version. The user interface is built using moderns Spring MVC. Because the application already uses the latest Spring version and is already using JPA you could say this application is halfway of migration step two.

We will migrate this example application step-by-step to a full Java EE 6 application using the following approach:

  1. Upgrade the web UI to JSF
  2. Replace the Data Access Layer to EJB / JPA
  3. Migrate AOP to CDI interceptors
  4. Migrate JMX
  5. Migrate JDBC Templates
  6. Remove Spring
  7. Integration testing

This article is the first of a series and only discusses the general approach and migrate the web layer. In the next articles we will migrate the rest of the code. This article focusses on step two and three in the migration approach discussed above. In the final article in the series we will have replaced all Spring components and can finish by removing Spring entirely.

When migrating your own applications you don’t have to stick to this approach exactly; this strongly depends on the application. It is also not required to focus on a specific technology (e.g. data access) at any point, and integration testing should be something you work on constantly.

The example application is available at github: https://github.com/paulbakker/petclinic. Each step can be traced back as a change set. We highly recommend cloning the repository and keeping the code next to the article.

Migrating the web UI

The goal of this step is to replace Spring Web MVC by JSF and CDI while keeping the functionality more or less the same. This might be a realistic scenario in some projects if there is a lot of unmaintainable legacy code. When projects grow and teams are too large this often happens, no matter what technology is used. The other scenario might be that new functionality must be added to an existing application, but the current technology stack is outdated. Unfortunately this is already the situation if the old-style Spring Web MVC (pre Spring 2.5) is used.

JSF is probably the part of Java EE that receives most critics. It’s fair to say that JSF is not perfect for each situation, but to our opinion; no web framework is. It depends a lot if you are building an intranet application for 50 users, or a high profile news site that has a  hundred thousand hits each second. JSF makes it easy to build the first type of application, but impossible to do the second. Whatever application you are building, choose the web technology fit for the situation. In the final article of the series we will discuss an approach where the UI is entirely client-side. For this article we will focus on JSF however, because it works well for this type of application.

To show some different interesting capabilities of Java EE 6 we changed the UI a little at some places. After this step we should have removed the following:

  • The web and validation packages
  • All configuration in web.xml
  • petclinic-servlet.xml
  • All JSP files

Step 1 – Install JSF

First we need to add JSF and CDI to our project. To work with Java EE we need only one new POM dependency that contains all the Java EE 6 APIs. An application server includes the implementations of these APIs so the scope should be “provided” (not included in the WAR file).

<dependency>
 <groupId>org.jboss.spec</groupId>
 <artifactId>jboss-javaee-6.0</artifactId>
 <version>1.0.0.Final</version>
 <type>pom</type>
 <scope>provided</scope>
</dependency>

We also need an empty faces-config.xml file to turn on JSF in the WEB-INF folder.

<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_2_0.xsd"
version="2.0">
</faces-config>

To turn on CDI we need an empty file beans.xml in the WEB-INF folder. As a last step we also need to upgrade the web.xml to the latest version so that Servlet 3.0 becomes active and JSF can register itself automatically. Just change the versions in the namespaces to do so:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

These steps can be simplified by using JBoss Forge. This doesn’t create any lock-in on Forge; it is designed to work on standard Maven projects.

Start Forge and cd into your project and simply type:

$ setup faces
***SUCCESS*** Installed [forge.spec.servlet] successfully.
***SUCCESS*** Installed [forge.spec.jsf] successfully.
? Do you also want to install CDI? [Y/n] Y
***SUCCESS*** Installed [forge.spec.cdi] successfully.
? Do you also want to install the Faces servlet and mapping? [y/N] n
***SUCCESS*** JavaServer Faces is installed.
Wrote /Users/paul/tmp/forge-projects/jsftest/src/main/webapp
Wrote /Users/paul/tmp/forge-projects/jsftest/pom.xml
Wrote /Users/paul/tmp/forge-projects/jsftest/src/main/webapp/WEB-INF/web.xml
Wrote /Users/paul/tmp/forge-projects/jsftest/src/main/webapp/WEB-INF/faces-config.xml
Wrote /Users/paul/tmp/forge-projects/jsftest/src/main/webapp/WEB-INF/beans.xml

Forge will add the Maven dependency and create the required files.

Step 2 - JSF page template

In our new pages we want to keep the same look & feel like before. While you need includes for this in JSP we have a much cleaner template mechanism in JSF. A template is just a JSF page that contains defines page specific blocks using “ui:define”.

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
  <title>Simple JSF Facelets page</title>
  <h:outputStylesheet library="styles" name="petclinic.css"/>
</h:head>
<h:body>
  <div id="main">
    <ui:insert name="content"/>
    <table>
     <tr>
     <td><a href="/">Home</a></td>
     <td align="right">
      <h:graphicImage library="images" name="springsource-logo.png"/>
     </td>
    </tr>
  </table>
 </div>
</h:body>
</html>

Something to notice is the use of a resource library in the outputStylesheet and graphicImage. It has always been cumbersome to correctly reference images and stylesheets without getting problems with the relative location of files. When using a resource library you simply put all files into a directory under the “resources” directory. The name of the directory will be the name of the library. JSF will create the correct urls when rendering pages. You can use the same mechanism in CSS files:

background-image: url(#{resource['images:banner-graphic.png']});

To use this template you define a composition in a xhtml page.

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" template="template.xhtml">
  <ui:define name="content">
   Content within a template.
  </ui:define>
</ui:composition>

Step 3 - Integrate Spring and CDI component models

We are now ready to start implementing use-cases. Let’s start with the simple vets overview page. To implement this page we need a new xhtml file and a new class that feeds data into the page. To retrieve the list of vets we want to re-use our existing DAO implementation, which of course is a Spring bean.

What we want up with is the following:

@Named
@RequestScoped
public class VetsController {
  @Inject
  private Clinic clinic;
  public Collection<Vet> getVets() {
    return clinic.getVets();
  }
}

.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" template="template.xhtml">
<ui:define name="content">
 <h:dataTable value="#{vetsController.vets}" var="vet">
  <h:column>
   <f:facet name="header">Name</f:facet>
   #{vet.firstName} #{vet.lastName}
  </h:column>
  <h:column>
   <f:facet name="header">Specialities</f:facet>
   <ui:repeat value="#{vet.specialties}" var="speciality">
    #{speciality.name}
   </ui:repeat>
   <h:outputText rendered="#{vet.nrOfSpecialties == 0}" value="none"/>
  </h:column>
 </h:dataTable>
</ui:define>
</ui:composition>

The xhtml page uses the VetsController from Expression Language and the VetsController injects the Clinic DAO. There we have a problem however; if CDI creates an instance of Clinic like it would normally it will not work correctly. The Clinic implementation (EntityManagerClinic) requires all kind of Spring configuration such as a data source and entity manager. Of course we could migrate this code to Java EE 6, but it would be unrealistic in a large application to do so through all layers. For now we want the Clinic to just work as it used to do, and use this code from our new CDI bean. Technically this requires us to integrate the Spring and CDI component models.

For this to work we need a CDI extension that retrieves bean instances from the Spring application context and publishes those instance to CDI. You could easily write such an extension yourself, the presentation contains an example of this: https://github.com/paulbakker/migrating-spring-to-javaee/blob/master/src/main/java/demo/framework/StartupListener.java

You don’t have to implement this yourself however, the Seam Spring module already does this for you. Seam 3 is a set of CDI extensions that adds functionality to Java EE 6 in a standard way. Seam 3 is modular, you only depend on the module that you actually use, so the lock-in you create by using such a module is very low. In the example application we use Seam Spring to create the integration between CDI and Spring.

There is one additional difficulty in the way the PetClinic works. Because the PetClinic is a web application it creates a Spring WebApplicationContext at application startup time. To avoid creating bean instances twice we want to use this WebApplicationContext to retrieve bean instances to publish to CDI. The CDI bean discovery events are fired before the WebApplicationContext is created however which makes it impossible to automatically publish all Spring beans as CDI beans at application startup. There are different approaches to deal with this, but the most straightforward approach is to use CDI producers to publish Spring beans. You do need to write a producer for each Spring bean that you want to use in CDI, but this also keeps the process very explicit.

When using Seam Spring you can write producers as follows:

public class WebApplicationContextProducer {
  @Produces
  @SpringContext
  @Configuration(locations = "classpath:applicationContext-jpa.xml")
  ApplicationContext context;
  @Produces
  @SpringBean
  Clinic clinic;
  @Produces
  @SpringBean
  ClinicReporting clinicReporting;
}

Of course we also need to add Seam Spring to our POM file. The Seam modules can be found in the JBoss Maven repository.

<dependency>
  <groupId>org.jboss.seam.spring</groupId>
  <artifactId>seam-spring-core</artifactId>
  <version>3.1.0-SNAPSHOT</version>
</dependency>
<dependency>
  <groupId>org.jboss.seam.solder</groupId>
  <artifactId>seam-solder</artifactId>
  <version>3.0.0.Final</version>
</dependency>
<repository>
  <id>JBOSS_NEXUS</id>
  <url>http://repository.jboss.org/nexus/content/groups/public</url>
</repository>
</repositories>

To prevent CDI from creating instances of the Clinic and ClinicReporting itself we need to “veto” them. This can be done using Seam Solder by creating a page-info.java file in the package that contains the classes.

@Veto
package org.springframework.samples.petclinic.dao.jpa;
import org.jboss.seam.solder.core.Veto;

That’s all we need to do to integrate CDI and Spring! The @Inject Clinic in our CDI bean now works.

Step 4 - Migrating search owners

The search owners use case is very easy to migrate, this can be done using a plain JSF data table and a request scoped managed bean. To make things a bit more interesting we improved the searching process with some AJAX; whenever a user starts typing a name the list should be filtered.

<h:inputText value="#{ownerController.lastname}" id="lastnameInput">
  <f:ajax event="keyup" render="owners" execute="@this"/>
</h:inputText>
<h:dataTable value="#{ownerController.owners}" var="owner" id="owners">

....

</h:dataTalbe>

Step 5 - Migrating owner details

Owner details is a more interesting use case. After selecting an owner the owner details are shown, including the owner’s pet. From there, a user can edit the owner details, and add/edit pets. In the example application this is implemented in a stateless way by passing around the owner id with each request. There is nothing wrong with this approach, but can be implemented simpler when using a stateful programming model which is possible with Java EE 6. A stateful approach is not always a good choice because you loose bookmarkability of pages because the pages need state set by other pages.

Bookmarkability in this example is not an issue however so we can have the benefit of a simpler programming model.

When working with state in web applications people would generally use the http session to store state. Java EE 6 has something better though; Conversations. A conversation can be described as a sub-session; isolated data within a session identified by an id with their own time-out. Conversations prevents problems when using multiple browser tabs because of the explicit id, and reduce memory leaks because there is a clear start and end point for each conversation.

The basic structure will be that a conversation is started whenever an owner is selected. The conversations ends when the user returns to the find owner screen. Within the conversation we can simply keep variables in memory without passing around ids or re-loading data from the database.

In the code below you see how a single class is used to handle all owner related functionality.

@Named
@ConversationScoped
public class OwnerDetailsController implements Serializable {
  @Inject
  transient Clinic clinic;
  @Inject
  Conversation conversation;
  private boolean edit = false;
  private Owner owner;
  private Pet pet;
  public String showOwner(Owner owner) {
  conversation.begin();
  this.owner = owner;
  return "showowner.xhtml";
}
public String newPet() {
  pet = new Pet();
  owner.addPet(pet);
  return "editpet.xhtml";
}
public String editPet(Pet pet) {
this.pet = pet;
return "editpet.xhtml";

}

public Collection<PetType> getPetTypes() {
  return clinic.getPetTypes();
}
public String savePet() {
  clinic.storePet(pet);
  return "showowner.xhtml?faces-redirect=true";
}
public String toOverview() {
  conversation.end();
  return "findowner.xhtml?faces-redirect=true";
}
public Owner getOwner() {
return owner;
}
//Getters and setters
}

The owner field contains the currently selected owner and the pet field contains the currently selected pet (or a newly created pet). In the xhtml pages we can now simple reference those fields:

<h:inputText id="nameInput" value="#{ownerDetailsController.pet.name}"/>

The conversation is started by clicking on an owner in the find owner screen:

<h:commandLink action="#{ownerDetailsController.showOwner(owner)}" value="#{owner.firstName} #{owner.lastName}"/>

In the edit pet screen there is a drop down field to select the type of pet which is set as a PetType on the Pet entity. A select tag in HTML sends a single value back to the server. The problem here is that PetType is a complex type, and JSF can’t know how to identify a PetType as a single string value. Spring obviously has the same problem and uses Editors to convert from string to complex type and vice versa. JSF uses Converters which do basically the same.

A Converter implements two methods; one to convert a complex type to a String and one for conversion the other way around.

@FacesConverter("petTypeConverter")
public class PetTypeConverter implements Converter {
@Inject
Clinic clinic;
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
  for (PetType type : clinic.getPetTypes()) {
    if(type.getName().equals(s)) {
    return type;
    }
}  throw new ConverterException("Couldn't find pet type: " + s);
}

public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o) {
    PetType petType = (PetType) o;
    return petType.getName();
  }
}

The converter can then be used in the select box.

<h:selectOneMenu value="#{ownerDetailsController.pet.type}" id="typeInput">
  <f:converter converterId="petTypeConverter"/>
  <f:selectItems value="#{ownerDetailsController.petTypes}"/>
</h:selectOneMenu>

Although this code looks very straight forward there is a problem; it doesn’t work. Due to a bug in the JSF specification, dependency injection doesn’t work in Converters. We do need the Clinic to do the conversion however. Of course there are all sorts of work arounds possible, but dependency injection makes most sense. To fix this issue we will use the Seam Faces CDI extension. By simply having Seam Faces on the classpath we can use injection in Converters again. Besides fixing this issue there are a lot of other goodies in Seam Faces which are not discussed here, but it’s worth to have a better look at.

<dependency>
  <groupId>org.jboss.seam.faces</groupId>
  <artifactId>seam-faces</artifactId>
  <version>3.0.2.Final</version>
</dependency>

Alternatively you can work around the problem by using a method to reference the Converter instead of a converterId. The converter is just a normal CDI bean in that case, and injection does work.

<h:selectOneMenu value="#{ownerDetailsController.pet.type}"  id="typeInput" converter="#{ownerDetailsController.petTypeConverter}">
  <f:selectItems value="#{ownerDetailsController.petTypes}"/>
</h:selectOneMenu>
@Inject PetTypeConverter petTypeConverter;
public PetTypeConverter getPetTypeConverter() {
  return petTypeConverter;
}

Step 6 - Validation

Although Spring 3.0 has support for the Bean Validation specification the example application does not make use of this. Validation is implemented using implementations of Spring’s Validator interface. Bean Validation is a more DRY mechanism because both JPA and JSF can use the same validation rules. Migrating the old validation rules to Bean Validation  means adding annotations on our entity classes. The Bean Validation specification already describes a whole bunch of annotations and makes it easy to define new annotations yourself. However, you can get some more out-of-the-box rules by using Hibernate Validator. This library includes annotations such as @Email, @NotEmpty etc. Add Hibernate Validator to the Maven dependencies.

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>4.2.0.Final</version>
  <scope>provided</scope>
</dependency>

Alternatively you can use JBoss Forge to do so:

$ setup validation
Warning:  The encoding 'UTF-8' is not supported by the Java runtime.
***SUCCESS*** Installed [forge.spec.validation] successfully.
Which version of hibernate-validator would you like to use?
1 - [org.hibernate:hibernate-validator:::4.1.0.Final]
2 - [org.hibernate:hibernate-validator:::4.2.0-SNAPSHOT]
3 - [org.hibernate:hibernate-validator:::4.2.0.Beta1]
4 - [org.hibernate:hibernate-validator:::4.2.0.Beta2]
5 - [org.hibernate:hibernate-validator:::4.2.0.CR1]
6 - [org.hibernate:hibernate-validator:::4.2.0.Final]
7 - [org.hibernate:hibernate-validator:::4.3.0-SNAPSHOT]*
? Choose an option by typing the number of the selection [*-default]  [0] 6
Warning:  The encoding 'UTF-8' is not supported by the Java runtime.
Wrote /Users/paul/tmp/forge-projects/jsftest/src/main/resources/META-INF/validation.xml
Wrote /Users/paul/tmp/forge-projects/jsftest/pom.xml

Now we can add constraints to domain classes by annotating it’s fields.

public class Owner extends Person {
@NotEmpty
private String address;
@NotEmpty
private String city;
@NotEmpty @Pattern(regexp = "^[0-9]+$", message = "Only digits are allowed")
private String telephone;

JSF automatically triggers up these constraints when submitting data. You do need to display error messages however using the “h:message” tag.

Last Name: <h:message for="lastnameInput"/><br/>
<h:inputText value="#{newOwnerController.owner.lastName}" id="lastnameInput"/>

Step 7 - RESTful web services

The list of vets can also be retrieved as XML or JSON. While RESTful web services are implemented in your web controllers when using Spring we have a separate specification for this in Java EE 6 (JAX-RS). Besides the more clear separation between web controllers and web services in Java EE 6 the programming model is very similar to Spring. First of all we need to enable JAX-RS by extending the Application class. We also annotate this class to define the root url for our web services. The class doesn’t have to be registered anywhere.

@ApplicationPath("rest")
public class RestApplication extends Application {
}

Now we have to implement our web service method.

@Path("vets")
@Stateless
public class VetsResource {
  @Inject
  Clinic clinic;
  @Produces({"application/xml", "application/json"})
  @GET
  public Collection<Vet> listVets() {
    return clinic.getVets();
  }
}

Similar to Spring we can return our own data types. We annotate our classes with JAXB annotations to specify the mapping between Java and XML/JSON.

@XmlRootElement
public class Vet extends Person {
  ....
}

Step 8 - URL rewriting

One of the really nice things about Spring Web MVC is that application URLs are by default “pretty”. “/vets” is obviously nicer then “/faces/vets.xhtml”. JSF does not support this out of the box, but with the help of PrettyFaces we can easily add this. First of all we need the PrettyFaces dependency in Maven.

<dependency>
  <groupId>com.ocpsoft</groupId>
  <artifactId>prettyfaces-jsf2</artifactId>
  <version>3.3.2</version>
</dependency>

PrettyFaces doesn’t have to be registered, the only thing left to do is configure our application URLs. Create a file “WEB-INF/pretty-config.xml”. In this file you configure rules for rewriting pretty URLs to JSF URLs. Alternatively you can use JBoss Forge to create the dependency and configuration file.

$ setup prettyfaces

Install PrettyFaces for which technology?

1-[JSF 1.1 and Servlet <= 2.3]

2 - [JSF 1.2 and Servlet >= 2.4]

3 - [JSF 2.0 and Servlet >= 2.5]

4 - [Java EE 6 and Servlet >= 3.0]*

? Choose an option by typing the number of the selection [*-default]  [0] 4

Install which version?

 
  ....
  14 - [com.ocpsoft:prettyfaces-jsf2:::3.3.2]
  15 - [com.ocpsoft:prettyfaces-jsf2:::3.3.3-SNAPSHOT]
  16 - [com.ocpsoft:prettyfaces-jsf2:::4.0.0-SNAPSHOT]*
 ? Choose an option by typing the number of the selection [*-default]  [0] 15
Warning:  The encoding 'UTF-8' is not supported by the Java runtime.
Wrote /Users/paul/tmp/forge-projects/jsftest/src/main/webapp/WEB-INF/pretty-config.xml

For the example application the pretty-config file looks as follows.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.3-SNAPSHOT"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.3-SNAPSHOT http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.3-SNAPSHOT.xsd">
    <url-mapping id="home">
        <pattern value="/"/>
        <view-id value="/faces/welcome.xhtml"/>
    </url-mapping>

    <url-mapping id="vets">
        <pattern value="/vets"/>
        <view-id value="/faces/vets.xhtml"/>
    </url-mapping>

    <url-mapping id="searchowners">
        <pattern value="/owners"/>
        <view-id value="/faces/findowner.xhtml"/>
    </url-mapping>

    <url-mapping id="reports">
        <pattern value="/reports"/>
        <view-id value="/faces/reports.xhtml"/>
    </url-mapping>
</pretty-config>

Step 9 - Remove Spring Web MVC

Now that we successfully replaced all the web related code with Java EE 6 code we can remove a large part of the Spring code and configuration.

  • Remove the web and validation packages
  • Remove all JSP files
  • Remove petclinic-servlet.xml
  • Remove everything from web.xml

The code that we have thrown aways is of course replaced by new, to our opinion better, code. All the configuration is replaced by nothing but void however. One of the big advantages of Java EE 6 is that almost no configuration is required. Spring might be more flexible in the sense that it integrates with every possible framework, but this comes at the cost of a lot of required configuration. It’s not so much the writing of the configuration, this is easy, but understanding what an application does exactly is much more difficult.

What’s next?

So far we have only focussed on the web layer. In the next article of this series we will work on migrating the data access layer away from Spring. We will also introduce CDI as a migration solution for Spring Interceptors and AOP. Finally, we will show how to deal with JMX.

- Bert  Ertman & Paul Bakker

About the authors

Bert Ertman (@BertErtman) is a Fellow at Luminis in the Netherlands and a Sun/Oracle recognized Java Champion. Besides his day-job he is a JUG Leader for the Netherlands Java User Group (3500 members).

Paul Bakker (@pbakker) is a senior developer at Luminis Technologies in the Netherlands and a contributor on the JBoss Seam, Arquillian, and Forge projects.

Both authors have extensive experience in building enterprise applications using a variety of technologies ranging from the pre-J2EE, J2EE, Spring, and modern Java EE technologies. They have been discussing the use of new enterprise technologies regularly and had endless discussions on Spring vs. Java EE. Currently, they believe that both new, green field, enterprise applications, and large-scale maintenance migration on legacy apps can be done best using Java EE 6 technology. The authors have been evangelizing Java EE (6) technology at various conferences around the world, including J-Fall, Jfokus, Devoxx, and JavaOne. This series of articles is based upon their well-received JavaOne 2011 presentation titled “Best Practices for Migrating Spring to Java EE 6”.


Disclaimer: The views and opinions expressed in this article are those of the authors and do not necessarily reflect the official policy or position of Red Hat, Inc. Examples of analysis performed within this article are only examples. Assumptions made within the analysis are not reflective of the position of Red Hat, Inc.

,

About rayploski

I'm lucky enough to have a dream job. I run developer strategy for Red Hat.

View all posts by rayploski

5 Comments on “Article Series: Migrating Spring Applications to Java EE 6 – Part 2”

  1. srikanth ganta Says:

    Reblogged this on Srikanth's Blog.

    Reply

  2. Ken Rimple Says:

    Interesting read.

    A note on “legacy” JdbcTemplate – JdbcTemplate is extremely helpful in simplifying and reducing JDBC coding errors. You can even use it with a plain-old-datasource within Java EE if you want.

    I know Java 7 supports try with resources, and jdbc 4.1 has closeable connections, resultsets and statements, but there still is no developer productivity gain from moving off of JDBC Template to standard JDBC.

    What would the authors suggest? Writing SQL statements within JPA and calling the SQL Execution directly from the entity manager? I think that’s reasonable, but it doesn’t cover all cases as well, such as the nice row mapping, row processing and transformation APIs they provide in the template.

    Also, sometimes you just can’t use JPA on a legacy application – when the schema is hopelessly tangled, too complex to resolve normal queries with, are accessed via stored procedures, etc. You wouldn’t suggest that all applications be re-written to just support JPA mappings, would you?

    Finally, the “typical” spring application isn’t in my view. Sure, there are some older XML-driven Spring apps, but Kodo? Also, abuse of AOP is about as bad as abuse of EJBs. Nobody in their right mind does this (unless it is their first crack at Spring and they feel AOP is their hammer). Most of the AOP wrapping is done by the container automatically to provide security and transaction support.

    Thanks for the article. I am on the Spring side of things, but it’s useful to see how you would approach porting from Spring to something else. Sometimes we have clients who insist on a particular platform.

    Ken

    Reply

  3. Peter Janssen Says:

    Very interesting series! One request: epub?

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 115 other followers

%d bloggers like this: