The definitive guide to Vaadin 7 + Maven + Tomcat + IntelliJ IDEA with HotSwap deployment!

Introduction

Being in the process of moving from Eclipse to IntellJ IDEA, I was looking for a way to set up a new Vaadin 7 project (or actually a “module” as it’s called in IntelliJ) using Maven. I wanted to be able to deploy to Tomcat, preferably in a short cycle.

As I had to put together information from several sources and figure out some things by myself, I’m presenting the result of my research here.

Here we go:

1. Create a Maven project/module from the archetype

Either use an existing project or a new empty project in which you create a Maven module, or create a new Maven project. Whatever you choose, keep in mind that if you create a Maven (or any other) project and don’t change the name of the module, by default it will have the same name as the project and its root folder will be the same as the project root folder. If you plan to add more modules later this may not be what you want.

I chose to create a new Maven module in a new empty project that I created:

Choose File -> New Module. Select Maven. If not already present, add the archetype from group com.vaadin and with artifact id vaadin-archetype-application. For the version, just look up the latest one.

Create a new Maven module from the archetype.
Create a new Maven module from the archetype.

2. Adjust the POM

IDEA will have already opened the pom.xml file automatically. There is one change you must make: find the commented out dependency to the vaadin-client-compiler and uncomment it:

Uncomment the vaadin-client-compiler dependency.
Uncomment the vaadin-client-compiler dependency.

3. Package the project using Maven.

Open the Maven Projects tool window either by hovering over the icon in the lower left corner or by typing Ctrl-Shift-A and searching for Maven Projects. Then open Lifecycle and double-click package:

Package the maven project.
Package the module from the Maven Projects tool window.

After a few minutes, the .war file should be built.

4. Configure the Tomcat server

If you haven’t already done this, you should at this point configure a new Tomcat server:

Choose Run -> Edit Configurations…, press the + icon and choose to add a new Local Tomcat Server.

Create a new run configuration for the local tomcat server.
Create a new run configuration for the local tomcat server.

Choose a name for the server and make sure to select ‘Update resources’ for the ‘On frame deactivation’ option:

Choose 'On frame deactivation: Update resources'
Choose ‘On frame deactivation: Update resources’

Go to the Deployment tab. Click the + icon here to add an artifact. Select the exploded version of the .war file and press OK.

Add the exploded .war as an artifact to the deployment configuration.
Add the exploded .war as an artifact to the deployment configuration.

5. Enable HotSwap deployment

You need to make sure HotSwap deployment is enabled in the settings:

Enable HotSwap.
Enable HotSwap.

6. Start server in debug mode

Now you’re ready to start the server in debug mode:

Start Tomcat in debug mode.
Start Tomcat in debug mode.

You should see the Vaadin sample application at http://localhost:8080/.

Now when you make a code change, you can just press Ctrl+Shift+F9 to recompile and the classes will be reloaded.

TDD – Avoid coupling implementation to test code

The old “classicist” vs “mockist” debate

I have recently read Martin Fowler’s “Mocks aren’t stubs” article, of which a big part is about the (what he calls) “classicist” vs “mockist” approaches to testing and TDD.

In short, it comes down to this:

  1. The “classicist” prefers to write mini-integration tests that test a group of classes together without resorting to test doubles (mocks, stubs and the like) for most things unless to replace calls to an external system such as a database or web service.
  2. The “mockist” prefers to test units (mostly classes) in complete isolation, replacing collaborators with test doubles.

Which side to choose when doing TDD

I personally lean more towards the “classicist” approach for the following reasons:

  1. The “mockist” approach often tightly couples the implementation to the test and tends to make the test brittle: changes to the code will often mean changes to the test even if they don’t change the behaviour in the bigger picture of collaborating classes. And when that happens, the test has had no use since it was meant to confirm that a refactoring was done correctly without introducing bugs.
  2. One of the main goals of writing automated tests is to catch bugs. My experience tells me that bugs usually occur when different parts are put together and would often not get caught by testing the parts in isolation.
  3. Another goal is to provide documentation. Indeed, by looking at test code, it should be clear what the expected result of a piece of code is, i.e. what business value it provides. It does not have to be clear what collaborators are called in what order: that should be clear when looking at the code under test.

The first one, the tight coupling, is the most important to me. In my opinion, while refactoring it often degrades the red bar in the test report to nothing more than a glorified “Are you sure?” type popup message. And the answer would be “No, I’m not”, since I wasn’t expecting the test to be failing since my refactoring should not have any effect on the end result.

In this recent talk by Ian Cooper called “TDD, where did it all go wrong”, he explains very well why this coupling is so bad and how it is against the original spirit of TDD, as designed by Kent Beck.

TimeZone handling with MyBatis and PostgreSQL

The problem

I don’t like time zones. If it were my call, they wouldn’t exist and UTC would be used everywhere. Needless to say, I like Daylight Savings Time even less. These things just cause headaches for programmers. But until I become president of Planet Earth, we’ll probably have to deal with them.

The easiest way is to do all backend processing and storage in UTC and only convert to a local time zone in the UI layer. This requires you to set the database’s time zone to UTC:

ALTER DATABASE mydb SET TIMEZONE='UTC';

So I was using MyBatis to insert and retrieve date and time information in a PostgreSQL database.  Even though my database was set to UTC and a java.util.Date is by definition UTC, the JDBC driver seemed to interpret the time with the wrong TimeZone.

Even setting the default java TimeZone to UTC using
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
didn’t completely resolve my issues. I don’t really know why not, but doing that isn’t such a good idea anyway.

The solution

Fortunately, MyBatis allows you to define your own type handler to get complete control over how the java type is converted, and JDBC allows to specify a Calendar object whose TimeZone should be used to convert the date/time information.

So the solution is simple: write a type handler for java.util.Date that uses a Calendar object with time zone UTC to store/retrieve a timestamp.

public class UTCDateTypeHandler implements TypeHandler<Date> {

    @Override
    public void setParameter(final PreparedStatement ps, final int i, final Date date, final JdbcType jdbcType) throws SQLException {
        if (date == null) {
            ps.setNull(i, jdbcType.TYPE_CODE);
        }
        else {
            Timestamp timestamp = new Timestamp(date.getTime());
            ps.setTimestamp(i, timestamp, getUTCCalendar());
        }
    }

    @Override
    public Date getResult(final ResultSet rs, final String columnName) throws SQLException {
        return rs.getTimestamp(columnName, getUTCCalendar());
    }

    @Override
    public Date getResult(final ResultSet rs, final int columnIndex) throws SQLException {
        return rs.getTimestamp(columnIndex, getUTCCalendar());
    }

    @Override
    public Date getResult(final CallableStatement cs, final int columnIndex) throws SQLException {
        return cs.getTimestamp(columnIndex, getUTCCalendar());
    }

    private static Calendar getUTCCalendar() {
        return Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    }
}

Then in the MyBatis configuration, register the type handler for java.util.Date and whatever SQL type you are using:

  <typeHandlers>
    ...
    <typeHandler handler="be.mediagenda.mybatis.UTCDateTypeHandler" javaType="java.util.Date" jdbcType="DATE"/>
    ...
  </typeHandlers>

Random thoughts to some degree related to Java development