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

July 2, 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.

Introduction

This is the fourth and final article in the series about Migrating Spring applications to Java EE. In the previous articles we have shown how to migrate the Spring Pet Clinic application to Java EE in a step-by-step approach. In the third article we completed the migration except for the use of some JDBC Templates (within Java EE) and integration tests. This article will show how to write integration tests and use native SQL queries when the Java Persistence Query Language isn’t sufficient. Finally, we will discuss an alternative approach to developing an HTML5 user interface.

Writing integration tests

What exactly is an integration test and why do we need it? You probably already know about unit testing. An important rule while writing unit tests is that you test units (classes) in isolation. All other classes that are used from the class that you are testing should be mocked. This way you have full control of the environment the code is tested in, and this is very important when trying to get good code coverage of your code. This concept works very well, but it has limitations. Some code only makes sense when it runs in it’s natural environment; the Java EE container. How would you test a JPQL query when you mock the database? Or how would you test CDI event producers/consumers when you are only testing a single class? Or transaction propagation configuration? These kinds of tests are called integration tests. To take it one step further, you just want to run a (small) part of your application in a controlled environment using a real application sever and a real database. Integration tests should not replace unit tests; they should complement each other.

Integration testing has always been very difficult in Java EE, but those times are past! JBoss Arquillian (http://arquillian.org) makes it easy to deploy a small part of your application and write tests that actually run in the container itself. Arquillian has support for most available containers, both embedded and remote containers. We will now setup Arquillian and test some of the key parts of the Pet Clinic example application.

Step 1 – Setup Arquillian

First we need the Arquillian APIs to be on the classpath by adding the dependency to the Maven POM file. Next we have to configure a container to test in. This is basically adding the required dependencies specifically for the container that you want to test in to the POM file. For this example we will use a remote JBoss AS7 container, but it is very well possible to test in multiple containers.

First we add the Arquillian and JUnit dependencies to the POM.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.jboss.arquillian</groupId>
      <artifactId>arquillian-bom</artifactId>
      <version>1.0.1.Final</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies> 
  <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
  </dependency>
</dependencies>

These dependencies are enough to actually write tests, but we did not setup a container yet. Container dependencies should be configured in Maven profiles, so that you can easily switch between different containers. This way you could run your tests on a whole bunch of containers from a build server for example.

Lets add the dependencies to test on a remote JBoss AS7 container. Remote means that the server is externally managed and already running. You can also choose embedded or managed containers. An embedded container for example can be a CDI container, with limited capabilities but extremely fast to start. Managed means you are using an external, non-embedded, container which is started and stopped as part of the test.

<profiles>
<profile>
<id>JBOSS_AS_REMOTE_7.X</id>
<dependencies>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-arquillian-container-remote</artifactId>
<version>7.1.1.Final</version>
</dependency>
</dependencies>
</profile>
</profiles>

Now that Arquillian is fully setup we can start writing tests. Let’s start by testing some JPA code. When testing JPA code you want to test against a real database to see if your queries are correct, and if they are returning the correct data.

Start by creating a new JUnit test with some extra annotations. In this case we want an EntityManager and the UserTransaction injected in the test so we can use JPA right from the test itself. Because the test will be running in the container we can just use CDI to do the injection, just like you would do in your production code.

@RunWith(Arquillian.class)
public class EntityManagerClinicTest {
    @Inject
    private Clinic entitymanagerclinic;

    @PersistenceContext
    EntityManager em;

    @Inject
    UserTransaction utx;

...

Instead of deploying your full application for testing, Arquillian uses the concept of micro deployments. A micro deployment is a deployment potentially containing only a few classes and configuration files. You only deploy what you are going to test. This makes deployments extremely fast which is important when you have a large set of tests.

In each test you have to define which classes and configuration files are part of the micro deployment. You do this from the @Deployment method using the ShrinkWrap API.

@Deployment
public static JavaArchive createDeployment() {
   return ShrinkWrap.create(JavaArchive.class, "test.jar")
           .addClass(EntityManagerClinic.class)
           .addClass(Clinic.class)
           .addPackage(Pet.class.getPackage())
           .addAsManifestResource("META-INF/persistence.xml", "persistence.xml")
           .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

In this case we only need to deploy the EntityManagerClinic, the Clinic interface, the entities and the persistence.xml configuration file. We also include an empty beans.xml file to enable CDI.

Now we can start writing some test code.

Let’s first test if we can list all owners using the findOwners() method.

@Test
public void testListOwners() {
  Collection<Owner> owners = entitymanagerclinic.findOwners("");
  assertNotNull(owners);
  assertEquals(1, owners.size());
  assertEquals(1, owners.iterator().next().getPets().size());
}

This code, once again, very much resembles using Clinic from production code. And it runs the same way too, because the test is deployed and ran in the actual application server. A problem that you always have to deal with while testing data access code is defining a set of test data. Tests should be independent and repeatable, so you have to make sure that tests always run against the same data set. We can simply use JPA in our test to insert a data set.

@Before
public void preparePersistenceTest() throws Exception {
  clearData();
  insertData();        
}

@After
public void commitTransaction() throws Exception {
  utx.commit();
}

private void clearData() throws Exception {
  utx.begin();
  em.joinTransaction();
  System.out.println("Dumping old records...");

  em.createQuery("delete from Pet").executeUpdate();
  em.createQuery("delete from Owner").executeUpdate();

  utx.commit();
}

private void insertData() throws Exception {
  utx.begin();
  em.joinTransaction();

  Owner owner = new Owner();
  owner.setFirstName("Paul");
  owner.setLastName("Bakker");
  owner.setAddress("Some address");
  owner.setCity("Some city");
  owner.setTelephone("123");

  Pet pet = new Pet();
  pet.setName("Donut");
  owner.addPet(pet);

  em.persist(owner);

  utx.commit();
  em.clear();
}

If you have many test classes that are using your entities you could of course create a base class that sets up the test data instead of writing that in each individual test class.

There is also an interesting Arquillian Persistence extension that integrates DBUnit in Arquillian where you can define your test data externally. You can find this extension on GitHub: https://github.com/arquillian/arquillian-extension-persistence.

Functional testing

In-container integration testing gives you a really nice way to test most of your code. But what about the web layer and the UI? Functional testing or testing the UI in general is always difficult. You have to deploy part of the application and then use something like Selenium to drive a browser and run tests directly on the running application. Setting up and writing tests in Selenium is not that easy. Luckily Arquillian can help out here again. There is an Arquillian extension called Arquillian Drone that enables you to drive Selenium directly from Arquillian tests.

Step 1 – Setup Arquillian Drone

First we need some new dependencies in our POM file to start using Drone in our test code.

<dependency>
    <groupId>org.jboss.arquillian.extension</groupId>
    <artifactId>arquillian-drone-bom</artifactId>
    <version>1.0.0.Final</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Next we also need some new dependencies in our test runtime configuration. These dependencies contain Selenium itself. You can add the dependencies to the Maven profile for the JBoss AS7 server.

<dependency>
    <groupId>org.jboss.arquillian.extension</groupId>
    <artifactId>arquillian-drone-impl</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.arquillian.extension</groupId>
    <artifactId>arquillian-drone-selenium</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.arquillian.extension</groupId>
    <artifactId>arquillian-drone-selenium-server</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-server</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>servlet-api-2.5</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.6.4</version>
    <scope>test</scope>
</dependency>

Step 2 – Create a functional test

Create a new Arquillian test and inject Selenium and the deployment URL into it.

@RunWith(Arquillian.class)
public class ClientTest {

    @Drone
    DefaultSelenium browser;

    @ArquillianResource
    URL deploymentURL;

    ....

The @Drone annotation gives you access to the Selenium API that you would use normally. Because you are deploying to a real container it’s important to know the url where the application is available (instead of hard coding it) because this can be different for different containers. The @ArquillianResource gives you exactly that.

Step 3 – Configure the micro deployment

Because we want to test the front-end of the application, we have to deploy part of the application containing everything to render pages. This is typically a little bit more than you would deploy for a data access related integration test, but we should still try to keep the deployments as small as possible.

@Deployment(testable = false)
public static WebArchive createDeployment() {
  return ShrinkWrap.create(WebArchive.class, "petclinictest.war")
          .merge(ShrinkWrap.create(GenericArchive.class).as(ExplodedImporter.class)
                  .importDirectory("src/main/webapp").as(GenericArchive.class),
                  "/", Filters.include(".*\\.*$"))
          .addClass(EntityManagerClinic.class)
          .addClass(UsageLogInterceptor.class)
          .addClass(UsageLogMBean.class)
          .addClass(Clinic.class)
          .addPackage(Pet.class.getPackage())
          .addAsResource("META-INF/persistence.xml", "META-INF/persistence.xml")
          .addAsWebInfResource(
                  new StringAsset("<faces-config version=\"2.0\"/>"),
                  "faces-config.xml")
          .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

Note that the deployment method now returns a WebArchive instead of a JavaArchive. Also note the testable=false parameter in the @Deployment annotation.

We import the complete “webapp” directory in the archive that contains all web resources such as xhtml pages. We also have to include a faces-config.xml file to start JSF.

Step 4 – Writing the actual tests

Now we can start using the Selenium API to load pages and assert data on it. There is nothing Arquillian specific about this, Arquillian just makes it way easier to bootstrap Selenium. When you run the tests you will see the actual browser pop up running the test like you would normally see.

@RunAsClient
@Test
public void testWelcomePage() {
    browser.open(deploymentURL + "/faces/welcome.xhtml");
    assertTrue("Welcome page", browser.isElementPresent("xpath=//a[text()='Find owner']"));
}

@RunAsClient
@Test
public void testFindOwners() {
    browser.open(deploymentURL + "/faces/findowner.xhtml");
    System.out.println(browser.getBodyText());
    assertTrue("Owners", browser.isElementPresent("xpath=//a[text()='Paul Bakker']"));
}

Of course we only tested a small part of the application in these examples, but writing more tests is just applying the same trick on different code. Arquillian gives the power to test all your code, and test your code in a realistic way. This will help you find bugs early and help you make sure you don’t introduce new bugs while making changes.

Migrating JDBC Templates

In the previous article we have shown how to use Spring JDBC Templates in a Java EE application. While this works well and might be exactly what you need, we are not big fans of JDBC Templates at all. JDBC Templates hardly give any abstraction on top of the database and you’re on your own for Object Relational Mapping. We strongly advise to use JPA wherever possible; it gives portability by abstracting most of the database specific SQL that you would need, and it does all the hard and painful work of object mapping. There are some valid use cases that require native SQL however. For example; some queries are just much more performant when using database specific features such as hierarchical queries. Luckily you only need those advanced database features for a small part of your application in most cases. In that case you should default to standard JPA for all the easy use cases such as CRUD, and fall back to native queries for the few advanced requirements. JPA has support for native queries, where you can use database specific SQL while query results are still mapped to objects by JPA. While JPA native queries are conceptually similar to JDBC Templates, you’re still using the same standardized API.

The only JDBC Template code left in the project is the ClinicReporting implementation. All though the example is trivial, it does show how to use native queries. Of course in this specific example we could just as easily write the query in JPQL, but it’s just to show how to use native queries.

First we make sure the JdbcClinicReporting class becomes an EJB so that we get transactions and JPA integration. We then use the EntityManager to create a native query.

@Stateless
public class JdbcClinicReporting implements ClinicReporting{
  @PersistenceContext
  EntityManager em;

  public int countVisitsAtDate(Date date) {
      String queryStr = "select count(*) from visits where visit_date = ?";
      Query query = em.createNativeQuery(queryStr, CountResult.class);
      query.setParameter(1, new Date());
      return query.getFirstResult();
  }
}

The second parameter passed to the createNativeQuery is a class that will hold the results of the query. This should be a class with getters/setters for each value in the query result.

public class CountResult {
    private int count;
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
}

This final code example concludes the series about migrating Spring applications to Java EE. If you followed the examples so far you have successfully turned your legacy Spring application into a light weight, fully portable, enterprise Java application. Congratulations! As we said in the beginning of the series, the migration steps set forward in these articles can be followed just up to any point as your business case allows for. Finally, as a little added bonus we’d like to conclude the series with a little bit of advise on how to make use of some Java EE techniques to modernize the front-end of your application to also better support mobile clients and leverage the powerful capabilities of the browser.

HTML 5 web clients

In the first part of the article series we migrated Spring Web MVC to JSF. Not everybody likes JSF. Most of the negativity about JSF is still from the JSF 1.x days, when there where some serious problems. For many types of applications JSF nowadays actually works very well. The stateful programming model is excellent for typical CRUD-like applications, and is on-par with popular frameworks such as Grails in terms of developer productivity. With the RichFaces project there is also nice support for mobile applications, especially if you need a mobile application based on your existing web application.

There is one thing that JSF is not good at though; large scale performance. The component based paradigm that JSF is built on gives a nice programming model, but is not fit for extremely large scale sites such as news sites. For these kinds of applications you should typically prefer a stateless model because it’s easier to scale. Remember that not every application has these requirements, every paradigm has it’s own ups and downs. In case JSF doesn’t fit your style of application very well, what alternatives do you have? Of course you could plug in any web framework on top of Java EE. There are several web frameworks that work very well together with Java EE. One way that we found very effective is using plain HTML5 clients on top of JAX-RS RESTful web services. Browsers are getting more and more powerful, and it makes sense to do more on the client side. Especially when doing mobile applications.

In the first part of the article we have shown JAX-RS as an excellent way of implementing RESTful web services. On top of a RESTful web service that works with JSON you can easily write a JavaScript client using jQuery for example. This approach becomes more and more popular and a lot of people are very successful doing so. If you don’t like writing HTML and JavaScript yourself, you could consider looking at JBoss Errai (https://www.jboss.org/errai). This project brings CDI to the client-side using GWT. Everything like dependency injection and events are supported. You write clients like you write server-side code, and you can do advanced JavaScript like server-side pushing.

, , ,

About rayploski

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

View all posts by rayploski

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

  1. dhartford Says:

    Part 1 through Part 4 for Spring to Java EE6 is a nice series, however I haven’t seen any metrics to show the gains of the conversion.

    Would it be possible to see some simple Jmeter scalability metrics (i.e. does the javaEE version scale better than the Spring version) if that was one of the gains before jumping to any UI changes?

    Reply

Trackbacks/Pingbacks

  1. Migrating from Spring to Java EE 6 – Part 4 | How to JBoss | Brent Sordyl's blog - July 3, 2012

    [...] Story: Migrating from Spring to Java EE 6 – Part 4 | How to JBoss) Like this:LikeBe the first to like this. arquillian, spring arquillian, ee6, spring [...]

  2. 20120822Migrate Spring Application to Java EE6阅读心得 | doublehero - August 22, 2012

    [...] http://howtojboss.com/2012/07/02/migrating-from-spring-to-java-ee-6-part-4/ [...]

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 117 other followers

%d bloggers like this: