Spring Boot: Controlling timezones with Hibernate

In this post I show how you, from a Spring Boot application, can control the timezone used by Hibernate when it communicates timestamps with the database.

This post is inspired by a very similar recent post by Vlad Mihalcea [1], Hibernate Developer Advocate at Redhat.

It’s basically the same subject – but with a Spring Boot focus. So read on, if you want to get a “ready-to-use” recipe for controlling the timezones used by JPA/Hibernate in your Spring Boot applications.

I will show the technique in the context of a Spring Boot 1.4.2 application.

Just looking for the solution? Then scroll down to Solution 2: Configuring Hibernate to control the timezone.

Motivation

On the job I was recently developing a JPA 2 powered database integration: I decided that the application should store timestamps in UTC. Effectively the same end result as deciding that it should run in the GMT timezone. UTC is strictly speaking not a timezone – if you want to be nitty-gritty [2].

It turns out that this is a very annoying situation. Until very recently, with Hibernate, you basically only had one solution: Configuring the JVM’s default timezone. More about that next.

Solution 1: Configuring the JVM’s default timezone

Here is one way to fix the problem: Put the JVM’s default timezone into UTC. Like this, if you launch a Spring Boot runnable JAR:

java -Duser.timezone=UTC -jar build/libs/springboot-hibernate-timezones.jar

Or from inside your Spring Boot application, like this:

@SpringBootApplication
public class Application {

  @PostConstruct
  void started() {
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
  }

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

}

You could also put the TimeZone code into the main method. But putting the TimeZone code into a @PostConstruct callback like this, ensures that it is also effective when you run tests or wrap up the application as a Web ARchive (WAR). Be careful about competing with other initializer methods that use JPA during startup.

In fact, as of writing this post (November 2016), setting the default timezone is the only truly portable solution for vanilla JPA solutions. JPA doesn’t allow you to control this.

If you use another JPA provider (than Hibernate) then this is still the way to go.

This solution works. But it is very invasive and has a few potential drawbacks.

Firstly, what if your JVM cannot be put into the timezone you desire for your database? Perhaps another default timezone is required by other parts of your application. Perhaps it is outside your control. That could easily be the case if your application is colocated with other applications in a shared application server for example.

Secondly, what if you need to access different databases – and they, for whatever reason, need timestamps to be stored in different timezones?

Solution 2: Configuring Hibernate to control the timezone

The previous solution is like solving the problem with a bazooka. Luckily, Vlad Mihalcea recently updated Hibernate itself to support this usecase. Even better:

The Hibernate specific configuration solution is a much more powerful solution

It is more powerful because you can choose to configure a specific SessionFactory (think JPA EntityManagerFactory) and even a specific Session (think JPA EntityManager). What a fantastic update! Find more details in Vlad Mihalcea’s post [1].

I have prepared a working Spring Boot example on GitHub – consult that to see the code in its entirety and true surroundings. These are the 2 steps you need to complete…

Step 1 of 2: Upgrade Hibernate

The Hibernate version shipped with Spring Boot 1.4.2 is 5.0.11.Final. That’s not new enough. So start by upgrading Spring Boot to use Hibernate 5.2.3.Final or newer.

From the example on GitHub – in Gradle:

...

// So we get Hibernates time zone configuration option (released October 2016):
ext['hibernate.version'] = '5.2.3.Final'

...

That’s how Hibernate get’s upgraded.

Step 2 of 2: Configure Hibernate to control the timezone

With Spring Boot this is a breeze. Add a property in application.properties:

spring.jpa.properties.hibernate.jdbc.time_zone = UTC

Done.

By the way: The example on GitHub uses a YAML file instead. It looks slightly different – but same principle in another syntax.

Test it

The example on GitHub includes a minimal test of the Hibernate configuration.

Firstly, a JPA entity:

@Entity
class Message {

  @Id // Don't do this at home...
  private String message;

  @Column
  private LocalDateTime created;

  // ... Getters and setters && a few constructors

}

Secondly, a JPA repository – Spring Data style:

interface MessageRepository extends CrudRepository<Message, String> {
}

And finally, the integration test:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaIntegrationTests {

  static {
    TimeZone.setDefault(TimeZone.getTimeZone("GMT+2"));
  }

  @Autowired
  private MessageRepository messageRepository;

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Autowired
  private Environment e;

  @Test
  public void testJpa() {

    //
    // Given
    //

    // 1) This is the datetime we will insert
    LocalDateTime localDateTime = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0, 0);

    // 2) This is the datetime we expect the database to receive
    LocalDateTime gmtDateTime = LocalDateTime.of(2016, Month.DECEMBER, 31, 22, 0, 0);

    //
    // When
    //

    messageRepository.save(new Message("Hello World from JPA", localDateTime));

    //
    // Then
    //

    Message fromDatabase = messageRepository.findOne("Hello World from JPA");

    // 1) Datetime is unchanged
    assertThat(fromDatabase.getCreated()).isEqualTo(localDateTime);

    // 2) We expect the database to store the datetime in the GMT timezone ( == UTC )
    jdbcTemplate.query("select " + formatDate(e, "created") + " from message", rs -> {
      assertThat(LocalDateTime.parse(rs.getString(1))).isEqualTo(gmtDateTime);
    });

  }

}

First, consider that the default timezone is set to GMT+2 (see the static initializer). Then notice that a LocalDateTime is created in this context. Finally notice the “Then” part: the database receives a LocalDateTime that is 2 hours before the LocalDateTime being inserted.

And there you have it: Hibernate automatically translates the LocalDateTime from GMT+2 into GMT (=UTC) when communicating with the database.

BONUS TIP: Getting the Hibernate configuration to work with MariaDB / MySQL

Well, that didn’t work for me.

To begin with at least. It turns out that MariaDB / MySQL by default runs in a useLegacyDatetimeCode=true mode. You need to deactivate it for Hibernate to be able to do it’s magic. Luckily that’s easy, just configure it in the JDBC connection URL:

jdbc:mysql://localhost:3306/mysql?useLegacyDatetimeCode=false

Why? I debugged the driver to find out what was happening. It turns out that the Calendar objects Hibernate send to the JDBC API gets completely ignored. When the driver runs in the useLegacyDatetimeCode=true mode, which is default. The driver get’s the argument – and then simply choose to make another Calendar like this: Calendar.getInstance(). The effect of that, is that the driver uses the timezone that is default to the JVM.

Notice that the MariaDB / MySQL JDBC drivers also support another argument: serverTimezone=TIMEZONEHERE. Set that to GMT, skip the Hibernate configuration, and you have another solution. This time, however, tightly bound to the specific driver.

How Hibernate controls the timezone

Hibernate controls the timezone on the JDBC API layer.

The example I created used a LocalDateTime. The JDBC API doesn’t support LocalDateTime, so Hibernate translates that into a java.sql.Timestamp before it sends it to the PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal) method.

Notice the Calendar argument. In Java Calendars are TimeZone aware. The Calendar Hibernate sends into the method is in the timezone that you specify.

Likewise, when Hibernate reads from the database again it sends the Calendar into ResultSet.getTimestamp(int columnIndex, Calendar cal).

I have illustrated this in a simulation – find it on GitHub too:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JdbcIntegrationTests {

  static {
    TimeZone.setDefault(TimeZone.getTimeZone("GMT+2"));
  }

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Autowired
  private Environment e;

  @Test
  public void testJdbc() {

    //
    // Given
    //

    // 1) This Calendar ensures that Timestamps are stored in the specified timezone:
    //    > Ignored when using useLegacyDatetimeCode=true (which is default for MariaDB) <
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    // 2) This is the datetime we will insert
    LocalDateTime localDateTime = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0, 0);

    // 3) This is the datetime we expect the database to receive
    LocalDateTime gmtDateTime = LocalDateTime.of(2016, Month.DECEMBER, 31, 22, 0, 0);

    //
    // When
    //

    jdbcTemplate.update("insert into message values (?, ?)", ps -> {
      ps.setString(1, "Hello World from JDBC");
      ps.setTimestamp(2, Timestamp.valueOf(localDateTime), cal);
    });

    //
    // Then
    //

    // 1) We expect to get the datetime back in the JVM's timezone:
    jdbcTemplate.query("select * from message", rs -> {
      assertThat(rs.getTimestamp("created", cal).toLocalDateTime()).isEqualTo(localDateTime);
    });

    // 2) We expect the database to store the datetime in the GMT timezone ( == UTC )
    jdbcTemplate.query("select " + formatDate(e, "created") + " from message", rs -> {
      assertThat(LocalDateTime.parse(rs.getString(1))).isEqualTo(gmtDateTime);
    });

  }


}

The test is almost the same as the JPA version. This time it uses raw JDBC to document the machinery.

Reflection

I am actually puzzled that the configuration now offered by Hibernate hasn’t already been baked into the JPA specification. I suggested it on Twitter for some of the top Hibernate/JPA influencers and it seems like they could see the point in that [3].

Who knows, one day we may have this feature in JPA?

References

[1] How to store timestamps in UTC using the new hibernate.jdbc.time_zone configuration property:
http://in.relation.to/2016/09/12/jdbc-time-zone-configuration-property/

[2] UTC – The World’s Time Standard:
https://www.timeanddate.com/time/aboututc.html

[3] Twitter – Why didn’t this feature go into JPA?
https://twitter.com/moelholm/status/794876824618749952

Tagged with: , , ,
Posted in Hibernate, Spring

Spring: Bean qualification

In this post I present how you can control a situation in which there are multiple beans that qualifies for an injection point in Spring.

The material here has been tested with Spring Framework 4.3.

The problem

Let’s first take a look at the problem. Imagine you have this interface:

public interface BusinessEventLogger {
}

And two different implementations of this. First this:

@Repository
public class DatabaseBusinessEventLogger implements BusinessEventLogger {
}

And then this:

@Repository
public class WebServiceBusinessEventLogger implements BusinessEventLogger {
}

Now, when you try to inject by the interface…

@Service
public class GreeterService {

  @Autowired
  private BusinessEventLogger businessEventLogger;

  public String sayHello(String caller) {
    businessEventLogger.log("Sending hello message to %s", caller);
    return String.format("Hello World, %s", caller);
  }

}

… then Spring will fail with a NoUniqueBeanDefinitionException. That is because Spring cannot decide which repository implementation is appropriate. After all, there are two equally valid bean candidates here.

Techniques that you can use to get back in control:

  • Static decisions:
    • Use the bean class
    • Use the injection target member name
    • Use the @Qualifier annotation
    • Use a custom qualifier annotation
    • Use @Primary
  • Runtime decisions:
    • Use @Profile
    • Use @Profile and @Primary

That should be enough to get you started. Notice the grouping. Some of the techniques require you at development time to know which bean is relevant. Other techniques allow you to defer the decision until runtime. The latter group is appropriate if the actual decision is environment specific for example.

I have prepared an example on GitHub that shows the problem and each of the solutions. It is based on Spring Framework 4.3 (via Spring Boot 1.4.1). And it is a multi module Gradle project. The problem scenario itself is illustrated in module 00_TheProblem. The solution scenarios are illustrated in the modules named something similar to 0x_TheSolution_abc.

Solution 01: Use the bean class

This technique is applicable if you, at development time, already know the specific bean you need:

@Service
public class GreeterService {

  @Autowired
  private WebServiceBusinessEventLogger businessEventLogger;

  public String sayHello(String caller) {
    businessEventLogger.log("Sending hello message to %s", caller);
    return String.format("Hello World, %s", caller);
  }

}

Notice that the class WebServiceBusinessEventLogger has been hardcoded here.

Solution 02: Use the injection target member name

This technique is applicable if you, at development time, already know the specific bean you need:

@Service
public class GreeterService {

  @Autowired
  private BusinessEventLogger webServiceBusinessEventLogger;

  public String sayHello(String caller) {
    webServiceBusinessEventLogger.log("Sending hello message to %s", caller);
    return String.format("Hello World, %s", caller);
  }

}

Notice the name of the member field being injected into: webServiceBusinessEventLogger. This name happens to match the bean name of the bean that  is-a WebServiceBusinessEventLogger.

A bit fragile huh? One day another developer may drop by and refactor the name to something else. If that happens – then the application won’t start anymore.

Solution 03: Use @Qualifier

This technique is applicable if you, at development time, already know the specific bean you need:

@Service
public class GreeterService {

  @Autowired @Qualifier("webServiceBusinessEventLogger")
  private BusinessEventLogger businessEventLogger;

  public String sayHello(String caller) {
    businessEventLogger.log("Sending hello message to %s", caller);
    return String.format("Hello World, %s", caller);
  }

}

Notice the use of Spring’s @Qualifier annotation. It tells Spring exactly which bean is needed – by specifying its name.

I think this solution is more robust than solution 02. But it is still a bit fragile. What if somebody decides to refactor the name of the WebServiceBusinessEventLogger class?

Solution 04: Use a custom qualifier annotation

This technique is applicable if you, at development time, already know the specific bean you need:

@Service
public class GreeterService {

  @Autowired @WebServiceStrategy
  private BusinessEventLogger businessEventLogger;

  public String sayHello(String caller) {
    businessEventLogger.log("Sending hello message to %s", caller);
    return String.format("Hello World, %s", caller);
  }

}

Notice the use of the @WebServiceStrategy annotation. This is a custom qualifier annotation. It tells Spring what bean is used. To make this work though, you first have to define the annotation:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface WebServiceStrategy {
}

(Notice the use of Spring’s @Qualifier here. Now it is being used as a meta-annotation)

And you will also have to add it to the bean:

@Component
@WebServiceStrategy
public class WebServiceBusinessEventLogger implements BusinessEventLogger {
}

You also need to do the same for the database logger.

This solution is as type safe as it gets. But at the expense of additional ceremony. It can make sense, if the abstraction of the qualifier annotation names is good enough.

Solution 05: Use @Primary

This technique is applicable if you, at development time, already know the specific bean you need. You put Spring’s @Primary annotation on the “primary” bean:

@Component
@Primary
public class WebServiceBusinessEventLogger implements BusinessEventLogger {
}

This will make the WebServiceBusinessEventLogger bean “win”.

Notice the difference from the previous solutions:

Using Spring’s @Primary annotation on a bean is a global decision: every injection point will get the chosen bean.

This may seem like a weird solution. And in production code – using it like this – perhaps it is. But this is not where @Primary shines. Rather:

The @Primary bean feature is interesting when used together with @Profile to activate the primary bean at runtime.

OR:

The @Primary bean feature is interesting when used for testing purposes.

If you haven’t thought about this before, then now is the time to read that again🙂.

For testing purposes you can use @Primary to make a test bean “win” over a business bean. Take a look at Baeldung’s article for further inspiration [1]. In that article @Primary is used with a @Bean factory method and @Profile to make a test bean have precedence over a business bean. @Profile for this scenario isn’t necessary – unless the test bean also gets picked up when you run the application normally. That is typically an IDE configuration issue: when your test *.class files are colocated with the normal business *.class files (I’ve seen that in Eclipse once or twice).

Solution 06: Use @Profile

This technique is applicable if you want to choose the bean at runtime.

If you are using Spring Boot you could, as an example, start the application with:

--spring.profiles.active=webservice 

… to activate the webservice profile. Or you could also do it from a test, like this:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("webservice")
public class GreeterServiceIntegrationTests {
}

Notice the use of @ActiveProfiles – that tells Spring to run the ApplicationContext with the webservice profile activated.

In order for this to work, you also need to tell the conflicting beans what profile they belong to. You use the @Profile annotation for that. Here’s how you would do it for the WebServiceBusinessEventLogger class:

@Component
@Profile("webservice")
public class WebServiceBusinessEventLogger implements BusinessEventLogger {
}

Notice @Profile. That annotation tells Spring to only add the bean to the ApplicationContext if the webservice profile is active. @ActiveProfiles is different: it’s a test specific annotation that you put on test classes to tell Spring what profiles to activate when running the tests.

Unless you do anything else: You still need to put the @Profile annotation on the database logger too. Otherwise there will still be a conflict when you run with the webservice profile active (since, now there are two active beans candidates). If you have more candidates – then you will have to put @Profile on them too.

Solution 07: Use @Profile and @Primary

This technique is applicable if you want to choose the bean at runtime. It is 90% similar to solution 06. But this solution doesn’t require you to put @Profile on all candidates – only on the one that you also choose to be @Primary:

@Component
@Profile("webservice")
@Primary
public class WebServiceBusinessEventLogger implements BusinessEventLogger {
}

That’s it. Nothing else. If you have more candidates – then you will have to put @Profile and @Primary on them too.

The difference to solution 06, is that in this solution, one bean acts as a default bean: namely the one without @Profile.

Conclusion

This post described different techniques to solving the situation where you have multiple bean candidates for an injection point. Some of them are appropriate if you can make the decision at development time. Others are appropriate if you would like the flexibility at runtime. All of them have been possible since Spring Framework 3.x.

I haven’t included:

  • XML examples
  • Standards based qualification examples (JSR330 standard annotations [2])
  • @Bean examples

They do provide some further alternatives to fulfil the mission. That is an exercise for the motivated reader🙂.

I would love to hear from you, if you believe that I have forgotten some other obvious techniques. Just leave a comment before you leave.

References

[1] Injecting Mockito Mocks into Spring Beans :
http://www.baeldung.com/injecting-mocks-in-spring

[2] What is the relation between JSR-299 and JSR-330 in Java EE 6? Do we need two DI APIS?:
http://www.adam-bien.com/roller/abien/entry/what_is_the_relation_between

Tagged with: , ,
Posted in Spring

Spring Boot and Gradle: Separating tests

In this post I will present 4 different approaches to separating unit tests from integration tests, so that they can be run independently of each other. Here’s the 4 different approaches:

  • Separation based on name patterns
  • Separation based on JUnit categories
  • Separation based on Spring’s @IfProfileValue
  • Separation based on different source directories

These approaches can easily be extended to apply to other test types as well (performance tests for example). Also, please note that:

Only one approach is specific to using Spring.

The remaining 3 approaches can just as well be used without Spring.

For each approach you will find a reference to a super simple GitHub based project. Consult the projects there to see the source code in its entirety and true surroundings. All projects are based on JUnit 4, Spring Boot 1.4 and Gradle.

Example code

This is the class being tested:

@Service
public class GreeterService {

  public String sayHello(String caller) {
    return String.format("Hello World, %s", caller);
  }

}

The unit test class instantiates it directly:

public class GreeterServiceTests {

  @Test
  public void sayHello_whenInvokedWithDuke_thenSaysHelloWorldDuke() {

    // Given
    GreeterService greeterService = new GreeterService();

    // When
    String greeting = greeterService.sayHello("Duke");

    // Then
    assertThat(greeting).isEqualTo("Hello World, Duke");

  }

}

Unit tests (such as the above) can be run from Gradle like this: ./gradlew test.

The integration test class uses Spring Boot like this:

@RunWith(SpringRunner.class)
@SpringBootTest
public class GreeterServiceIntegrationTests {

  @Autowired
  private GreeterService greeterService;

  @Test
  public void sayHello_whenInvokedWithDuke_thenSaysHelloWorldDuke() {

    // When
    String greeting = greeterService.sayHello("Duke");

    // Then
    assertThat(greeting).isEqualTo("Hello World, Duke");

  }

}

Integration tests (such as the above) can be run from Gradle like this: ./gradlew integrationTest.

Separation based on name patterns

Find the GitHub project here.

This approach expects you to partition tests using different names. I have chosen these patterns:

  • Unit test classes are suffixed with Tests
  • Integration test classes are suffixed with IntegrationTests

There are no changes to the test classes you have already seen. Gradle takes care of that. Here’s the relevant part:

...
apply plugin: 'java'
apply plugin: 'spring-boot'
...

test {
    useJUnit {
        exclude '**/*IntegrationTests.class'
    }
}

task integrationTest(type: Test) {
    useJUnit {
        include '**/*IntegrationTests.class'
    }
}

The important thing to remember here is that the patterns must end with .class. I hope you won’t fall into the trap of forgetting that detail now…

So, this is easy. All driven from Gradle. However, if developers uses an invalid suffix by mistake, then please note that this will result in the test classes’ test cases not being run at all. A bit dangerous.

Separation based on JUnit categories

Find the GitHub project here.

This approach expects you to use JUnit annotations on the test classes. Firstly, create interfaces representing the test types:

public interface IntegrationTest {
}

And:

public interface UnitTest {
}

Then annotate your tests using the JUnit @Category annotation. Here’s the unit test:

@Category(UnitTest.class)
public class GreeterServiceTests {

  @Test
  public void sayHello_whenInvokedWithDuke_thenSaysHelloWorldDuke() {
  ...
  }

}

Here’s the integration test:

@SpringBootTest
@RunWith(SpringRunner.class)
@Category(IntegrationTest.class)
public class GreeterServiceIntegrationTests {

  @Autowired
  private GreeterService greeterService;

  @Test
  public void sayHello_whenInvokedWithDuke_thenSaysHelloWorldDuke() {
  ...
  }

}

Lastly, tell Gradle when to run the tests:

...
apply plugin: 'java'
apply plugin: 'spring-boot'
...

test {
    useJUnit {
        includeCategories 'com.moelholm.UnitTest'
    }
}

task integrationTest(type: Test) {
    useJUnit {
        includeCategories 'com.moelholm.IntegrationTest'
    }
}

So, this is easy as well. And it is type safe – so it is not brittle with respect to different test class names. Although not super elegant: Now you have to declare weird marker interfaces – and remember to annotate your test cases accordingly by pointing to them from the @Category annotation.

For more information about JUnit categories – see [1].

Separation based on Spring’s @IfProfileValue

Find the GitHub project here.

This approach expects you to consistently use a custom annotation plus Spring’s SpringRunner on all classes – even unit tests.

Here’s how the unit test class looks:

@RunWith(SpringRunner.class)
@UnitTest
public class GreeterServiceTests {

  @Test
  public void sayHello_whenInvokedWithDuke_thenSaysHelloWorldDuke() {
  ...
  }

}

Here’s how the integration test class looks:

@RunWith(SpringRunner.class)
@IntegrationTest
public class GreeterServiceIntegrationTests {

  @Autowired
  private GreeterService greeterService;

  @Test
  public void sayHello_whenInvokedWithDuke_thenSaysHelloWorldDuke() {
  ...
  }

}

In addition to that you must also implement the annotations – they are simple though. Here’s the @UnitTest annotation:

@Retention(RetentionPolicy.RUNTIME)
@IfProfileValue(name="testprofile", value="unittest")
public @interface UnitTest {
}

Notice the @IfProfileValue annotation [2]. Read it like this: if there is a system property defined and it has value unittest, then it means that the test is enabled.

Here’s the @IntegrationTest annotation:

@Retention(RetentionPolicy.RUNTIME)
@IfProfileValue(name="testprofile", value="integrationtest")
@SpringBootTest
public @interface IntegrationTest {
}

Again you see the @IfProfileValue annotation. This time  the value is different though: integrationtest. Also notice how the @SpringBoot test annotation is used here as a meta-annotation. Having it here means that we don’t have to use it on the test classes also (in addition to the @IntegrationTest annotation and the @RunWith annotation).

The Gradle configuration is simple too:

...
apply plugin: 'java'
apply plugin: 'spring-boot'
...

test {
    useJUnit {
        systemProperty "testprofile", "unittest"
    }
}

task integrationTest(type: Test) {
    useJUnit {
        systemProperty "testprofile", "integrationtest"
    }
}

Notice how a system property is passed to the JVM – effectively activating either the @UnitTest or the @IntegrationTest annotations.

This approach is kind of like the one based on JUnit categories. But I think the test classes look a bit leaner. One minor issue, if at all, is that Spring is used for running the unit tests also. It means a minor initial overhead of a few seconds at most.

Separation based on different source directories

Find the GitHub project here.

This approach expects you to place unit tests in src/test/java and integration tests in src/integrationTest/java. No modifications to the test classes at all – no custom annotations, no categories.

Here’s how it is defined with Gradle:

...
apply plugin: 'java'
apply plugin: 'spring-boot'
...

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    // So that we can use JUnit and the test dependencies pulled in by Spring Boot
    // from 'src/test/java' as well as 'src/integrationTest/java':
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

sourceSets {
    // So that we can place source code in 'src/integrationTest/java':
    integrationTest {
        java {

            // So that we can compile against the business classes (GreeterService, ...):
            compileClasspath += main.output
            // So that we can compile against the libs used by the business classes:
            compileClasspath += main.compileClasspath

            // So that we can compile against the unit test classes (custom utilities fx):
            compileClasspath += test.output
            // So that we can compile against the libs used by the unit test classes (JUnit, Spring test support, ...):
            compileClasspath += test.compileClasspath

            // So that test- and business classes can be used at runtime:
            runtimeClasspath += test.runtimeClasspath

        }
    }
}

task integrationTest(type: Test) {

    // So that Gradle knows where the integration test classes are:
    testClassesDir = sourceSets.integrationTest.output.classesDir

    // So that Gradle knows which runtime class path to use:
    classpath = sourceSets.integrationTest.runtimeClasspath

}

Notice the comments – they highlight the relevant parts for getting it right.

This approach introduces another source directory layout and hence forces you to physically separate integration test classes from unit test classes. From a conceptual level I think this is the nicest model. But to be completely honest: getting the Gradle script “right” wasn’t super easy. And I bet you can find variants of this out there that does something slightly different. Or at least looks different.

In retrospective

There are at least these 4 ways that you can choose between. Each of them works fine – so choose the one that is most meaningful to you and your team.

References

[1] JUnit 4 Categories:
https://github.com/junit-team/junit4/wiki/categories

[2] @IfProfileValue JavaDoc:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/annotation/IfProfileValue.html

Tagged with: , , , , , ,
Posted in Spring

Spring Boot 1.4: Gherkin tests

In this post I show how you can implement Gherkin tests for Spring Boot 1.4.1. Here is an example of a Gherkin based test script:

screen-shot-2016-10-15-at-20-53-08

The FeatureScenarioScenario OutlineGiven, When, Then and And constructs are part of the Gherkin test language [1]. Such tests are popular in Behavior-driven development (BDD) and is meant as a common tool between users from the business and users from the development team [2].

The idea is that you can execute such a Gherkin script and get a test result (did it work or not?)

Notice the Gherkin language, there is nothing that prevents you from writing such tests even before the real business code exists. In fact it is a BDD best practice to write the tests before the feature gets implemented:

Imagine if you and the business wrote Gherkin tests as part of a User Story’s acceptance criteria…

I haven’t done this yet. But I bet there are a lot of BDD practitioners that have.

About the Spring Boot 1.4 example

I have prepared a Spring Boot 1.4.1 based example on GitHub. Consult that to see the code in its entirety and true surroundings. The example consists of:

  • The Gherkin test script you saw at the beginning of this post: It’s a script that tests a “greetings” RESTful(ish) resource.
  • The greetings resource: A super simple Spring MVC @RestController that accepts a caller name as input and emits a greeting message as output. This is the resource being tested.

I have used a 5 step recipe for making this work….

Step 1 of 5: Configure the build script

The example uses Gradle as it’s build technology. The Gherkin test support comes via the Cucumber-JVM test framework [3] and the Gradle Cucumber Plugin [4]. Here’s the Gradle script:

buildscript {
    repositories {
        mavenCentral()
        // So that the Gradle Cucumber Plugin can be downloaded:
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE")
        classpath("com.github.samueltbrown:gradle-cucumber-plugin:0.9")
    }
}

apply plugin: 'java'
apply plugin: 'spring-boot'
// So that the Gradle Cucumber Plugin gets activated:
apply plugin: 'com.github.samueltbrown.cucumber'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
    testCompile 'org.springframework.boot:spring-boot-starter-test'
    // So that you can use the cucumber API's for your step implementations:
    cucumberCompile 'info.cukes:cucumber-java:1.2.5'
    cucumberCompile 'info.cukes:cucumber-junit:1.2.5'
    cucumberCompile 'info.cukes:cucumber-spring:1.2.5'
}

cucumber {
    // So that you can generate some pretty (...) reports:
    formats = ['pretty', 'json:build/cucumber/cucumber.json', 'junit:build/cucumber/cucumber.xml', 'html:build/cucumber/html']

    // So that you can run all features/scenarios except for those annotated with @Ignore:
    tags = ['~@Ignore']
}

Notice the comments in the buildscript. They highlight what parts of the Gradle script are particularly interesting.

By using the Gradle Cucumber Plugin you now have the support for a new source folder structure:

src/cucumber
|--- java
|--- resources

You put the Gherkin step implementations in the src/cucumber/java directory and the Gherkin scripts under the src/cucumber/resources directory.

Step 2 of 5: Write the Gherkin tests

The Gherkin tests are written in a .feature file. In the example I put the following contents into src/cucumber/resources/greetingsResource.feature:

screen-shot-2016-10-15-at-20-53-08

This script contains 3 test scenarios.

The two first tests are based on the Scenario Outline and uses data from the Examples block. First column is the input we send to the greetings resource. Second and third columns are the expected outputs given that input. So: If we send in Duke to the greetings resource then we expect an HTTP status code 200 and a body with the message Hello World, Duke.

The third test is a Scenario that is not based on example input data. This test is just for fun😉 [5].

In the real world you would cover error conditions as well. So if you are testing a RESTful resource, like in this example, you would test for client errors 4xx etc.

Step 3 of 5: Implement the Gherkin steps test code

Here’s the step implementations for the Gherkin script:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration // Don't ask
public class GreetingsResourceSteps {

  @Autowired
  private TestRestTemplate restTemplate;

  private String caller; // input

  private ResponseEntity<String> response; // output

  @Given("I use the caller (.*)")
  public void useCaller(String caller) {
    this.caller = caller;
  }

  @When("I request a greeting")
  public void requestGreeting() {
    response = restTemplate
        .exchange("/greetings/{caller}", HttpMethod.GET, null, String.class, caller);
  }

  @Then("I should get a response with HTTP status code (.*)")
  public void shouldGetResponseWithHttpStatusCode(int statusCode) {
    assertThat(response.getStatusCodeValue()).isEqualTo(statusCode);
  }

  @And("The response should contain the message (.*)")
  public void theResponseShouldContainTheMessage(String message) {
    assertThat(response.getBody()).isEqualTo(message);
  }

}

Take a look at the class definition: this is where we tell the cucumber test framework to kickstart the Spring container. In fact it’s just like you would do in a typical Spring Boot 1.4 integration test: using the @SpringBootTest annotation. Said in another way: The Spring ApplicationContext will be launched prior to executing the Gherkin test scenarios.

Now take a look at lines 5+6: Here we inject Springs TestRestTemplate. We use this to send HTTP requests for our RESTful resource. Again, this is just like you would do in a typical Spring Boot 1.4 integration test.

Now take a look at the @Given, @When, @Then, and @And annotations: These define the methods implementing the steps. You can track them right back to the src/cucumber/resources/greetingsResource.feature file. Notice how we use simple regular expressions to map step input (fx caller values) to method parameters.

In case of errors, the steps throws ordinary java.lang.AssertionErrors via the awesome AssertJ library [6].

See? It almost looks like a normal Spring Boot integration test. One major difference is the need for storing intermediate state in the class itself (or somewhere else: fx a shared class). Well rest in the knowledge that any involved step classes, here GreetingsResourceSteps, are disposed after each Scenario. Said in another way: you have a fresh “steps” instance for each scenario.

You may also want to take a look at the @Before and @After cucumber annotations. They resemble the same from JUnit.

Step 4 of 5: Implement the feature being tested

Lastly, we get to the actual feature. It’s just the ordinary @RestController:

@RestController
public class GreetingsController {

  @GetMapping("/greetings/{caller}")
  public ResponseEntity<?> getGreeting(@PathVariable String caller) {

    if ("0xCAFEBABE".equalsIgnoreCase(caller)) {
      return new ResponseEntity<>(HttpStatus.I_AM_A_TEAPOT);
    }

    String greeting = String.format("Hello World, %s", caller);

    return new ResponseEntity<>(greeting, HttpStatus.OK);
  }

}

Ahem … I obviously wrote this controller after the Gherkin tests.

Step 5 of 5: Run the Gherkin tests and get the result

Thanks to the Gradle Cucumber Plugin, running the tests is a matter of:

./gradlew clean cucumber

Here is an example output:

screen-shot-2016-10-15-at-20-52-46

And here is an example output from the HTML generated report at ./build/cucumber/html/index.html:

screen-shot-2016-10-15-at-20-54-36

Using Jenkins as a CI server? You can find a bunch of cucumber plugins for that. Just point the plugins to your build/cucumber directory and you are good to go.

In retrospective

This example was all about testing a RESTful resource. But Gherkin style tests are not limited to that:

The Gherkin step implemention code could test anything

You could drive Selenium tests if you want to. Or Spring @Service beans. You decide.

The important thing is that it helps you and the business drive the right solution

References

[1] Gherkin language:
https://cucumber.io/docs/reference

[2] Behavior-driven development (BDD) on Wikipedia:
https://en.wikipedia.org/wiki/Behavior-driven_development

[3] Cucumber-JVM:
https://cucumber.io/docs/reference/jvm

[4] Gradle Cucumber Plugin
https://github.com/samueltbrown/gradle-cucumber-plugin

[5] 418
https://sitesdoneright.com/blog/2013/03/what-is-418-im-a-teapot-status-code-error

[6] AssertJ
http://joel-costigliola.github.io/assertj/

Tagged with: , , ,
Posted in BDD, Spring

Spring 4.3: Custom annotations

In this post I will show you how to bend the Spring Framework a little bit. In particular I will show you how you can make code like this:

@BusinessService
public class GreeterService {

  @LocalizedMessage("greeterservice.greeting")
  private Message greetingMsg;

  public String sayHello(@NotNull String caller) {
    return greetingMsg.format(caller);
  }

}

@BusinessService declares a perfectly valid Spring bean. It comes with the support for @NotNull parameter checks. @NotNull is from the bean validation API – no need to exercise too many keystrokes.

@LocalizedMessage is a perfectly valid injection capable annotation. Here we use that to inject a Message bean. This bean is context aware – it knows about the @LocalizedMessage annotation’s value attribute. With this information, Message is used from method sayHello to return Locale aware messages. ( AWESOME TIP UNLOCKED ).

Please note that:

just because you can doesn’t mean you should

Be careful about how creative you get when bending the Spring Framework. It could easily contribute to a codebase where only a few specialized authors understand what is really going on.

The next sections jumps right into the solution. I have prepared a working example at GitHub. Consult that to see the source code in it’s entirety and true surroundings. The example is based in Spring Boot 1.4.1 and Spring Framework 4.3.3.

Test cases

Here’s a few integration tests documenting how the service works:

@SpringBootTest
@RunWith(SpringRunner.class)
public class GreeterServiceIntegrationTests {

  @Autowired
  private GreeterService greeterService;

  @Test
  public void sayHello_whenInvoked_thenReturnsEnglishGreeting() {

    // Given
    String caller = "Duke";

    // When
    String greeting = greeterService.sayHello(caller);

    // Then
    assertThat(greeting).isEqualTo("Hello World, Duke");
  }

  @Test(expected = IllegalArgumentException.class)
  public void sayHello_whenInvokedWithNullArgument_thenThrowsIllegalArgumentException() {

    // Given
    String caller = null;

    // When
    greeterService.sayHello(caller);

    // Then
    // ( kapOOOf )
  }

  @Test
  public void sayHello_whenLocaleIsDanish_andInvoked_thenReturnsDanishGreeting() {

    // Given
    LocaleContextHolder.setLocale(new Locale("da", "DK"));
    String caller = "Duke";

    // When
    String greeting = greeterService.sayHello(caller);

    // Then
    assertThat(greeting).isEqualTo("Hej Verden, Duke");
  }

  @Before @After
  public void resetLocaleBeforeAndAfterEachTestCase() {
    LocaleContextHolder.setLocale(Locale.ENGLISH);
  }
}

From the second test case, notice that the service apparently knows how to validate the incoming parameter.
From the first and the third test cases, notice that the service is locale aware.

The @BusinessService annotation

The @BusinessService annotation is a custom “stereotype” annotation. Spring already has a bunch of stereotype annotations, including: @Service, @Controller, @Repository, and so on. But you can also add your own – as in the case of @BusinessService:

@Component
@Retention(RetentionPolicy.RUNTIME)
public @interface BusinessService {
}

The only thing that makes this annotation special is the @Component annotation. With that in place you can now use the @BusinessService annotation to declare Spring beans.

Spring Framework even allows you to meta-annotate your custom stereotype annotations with other framework annotations. For example with @SessionScope and @Transactional. If you annotate beans with such a composed annotation, then they would both be HTTP session scoped as well as transactional of nature. Consult the reference documentation for further information on that subject [1].

Enforcing @NotNull functionality

With the custom stereotype annotation in place you can now use it for something. What that “something” is, is entirely up to your imagination. But for this example I would like to ensure that @BusinesService components can benefit from automatic not-null parameter validation, by declaring @NotNull as hints. I have used Spring AOP for that in my example – it is extremely simple:

@Aspect
@Component
public class NotNullParameterAspect {

  @Before("@within(com.moelholm.spring43.customannotations.BusinessService)")
  public void before(JoinPoint caller) {

    Method method = getCurrentMethod(caller);

    Object[] parameters = caller.getArgs();

    Annotation[][] parameterAnnotations = method.getParameterAnnotations();

    // Throw exception if a parameter value is null AND
    // at the same time declares that it must be @NotNull
    for (int i = 0; i < parameters.length; i++) {
      Object parameterValue = parameters[i];
      Annotation[] annotationsOnParameter = parameterAnnotations[i];

      if (parameterValue == null && hasNotNullAnnotation(annotationsOnParameter)) {
        String msgTemplate = String.format("Parameter at index %s must not be null", i);
        throw new IllegalArgumentException(msgTemplate);
      }
    }

  }

  private boolean hasNotNullAnnotation(Annotation... annotations) {
    return Arrays.asList(annotations).stream().
              anyMatch(a -> a.annotationType() == NotNull.class);
  }

  private Method getCurrentMethod(JoinPoint joinPoint) {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    return signature.getMethod();
  }
}

The @Before annotation tells spring that the method should be executed before any invocation on beans that are annotated with @BusinessService. The method body, the advice, throws an IllegalArgumentException if a parameter is null and @NotNull annotated at the same time.

It’s just an example here. You could do anything in such an advice. In fact there are other types as well, including: @After, @Around, etc. Imagine what you could do with them…

Spring AOP is super powerful. I barely scratched the surface here. So if this is new to you – then check out the appropriate section in the reference documentation [2]. It can be a bit heavy – so remember to bring some dark coffee.

The custom dependency injection annotation: @LocalizedMessage

In a typical Spring application you pick between @Autowired, @Resource, @Value, @Inject when injecting a bean into another bean. But it’s super easy to create your own:

@Autowired
@Retention(RetentionPolicy.RUNTIME)
public @interface LocalizedMessage {

  String value() default "";

}

Take note of the @Autowired annotation. Without it, we would additionally have to specify one of the standard annotations on the injection targets as well, ie: @Autowired @LocalizedMessage Message message. Also take note of the value attribute – this is used to declare the name of the resource bundle key of interest.

Implementing the @LocalizedMessage support

In order for the Message bean to be injected it must be… well a bean. Here is how that is declared:

@Configuration
public class MessageConfig {

  @Bean
  public MessageSource messageSource() {

    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasename("messages");

    return messageSource;
  }

  @Bean
  @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  public Message message(InjectionPoint ip) {

    LocalizedMessage localizedMessage = AnnotationUtils
        .getAnnotation(ip.getAnnotatedElement(), LocalizedMessage.class);

    String resourceBundleKey = localizedMessage.value();

    return new Message(messageSource(), resourceBundleKey);
  }

}

Notice the message factory (/producer) method. It accesses the InjectionPoint class to fetch the resource bundle key of interest (fx. “greeterservice.greeting” declared in GreeterService). With that information and a valid MessageSource it then creates the Message bean.

Note that the scope of the message bean is prototype. It is very important for this case, as it ensures that each injection of Message is a new instance. Singleton scope here would have the effect that injections of Message beans would re-use the same instance (effectively tied to the same resource bundle message – despite the annotation key values at the injection targets).

In retrospective

The title claimed “Spring 4.3: Custom annotations”. To be honest, Spring Framework have had support for custom stereotypes for a long time. Many, many years. So that’s not new. Neither is the Spring AOP support I’ve shown.

But take a look at the custom dependency injection part. The InjectionPoint class is what makes this possible – and that’s a new thing, since Spring Framework 4.3 [3]. But even this part could have been implemented back in the old days: using a BeanPostProcessor [4]. But it would be a bit messy – at least compared to a simple @Bean factory method.

References

[1] @Component and further stereotype annotations:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-stereotype-annotations

[2] Aspect Oriented Programming with Spring:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html

[3] Spring 4.3: Introducing the InjectionPoint:
https://moelholm.com/2016/10/09/spring-4-3-introducing-the-injectionpoint/

[4] BeanPostProcessor JavaDoc:
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html

Tagged with: , ,
Posted in Spring

Spring 4.3: Introducing the InjectionPoint class

Did you know that Spring Framework 4.3 comes with a “hidden” gem: the InjectionPoint class ?

At the time of writing this post, InjectionPoint is nowhere to be found in the Spring Framework Reference Documentation [2].

About the InjectionPoint class

The InjectionPoint class [1] is a new feature that you can use in @Bean producer methods. It is specifically useful in @Bean methods that produces prototype scoped beans. And with it, you can get detailed information about the “places” into which your beans are injected. Said in another way:

@Bean methods can now be made context aware

If you know about Contexts and Dependency Injection (CDI) – then you may have heard about such a feature before. It is in fact an “oldie” in that context.

Example

I’ve prepared an example on GitHub – consult that for the source code in its full context. The example is based on Spring Boot 1.4 and therefore Spring Framework 4.3. Please bear with me …. in lack of a better example…

Imagine you want to inject a greeting into your GreeterService:

@Service
public class GreeterService {

  @Autowired @Greeting(language = Language.EN)
  private String greeting;

  public String sayHello(String caller) {
    return String.format("%s, %s", greeting, caller);
  }

}

… here is one way you could implement it:

@Configuration
public class MyBeanConfig {

  @Bean
  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  public String greeting(InjectionPoint ip) {

    Greeting greeting = findAnnotation(ip.getAnnotatedElement(),
                        Greeting.class);

    return (Language.DA == greeting.language()) ? "Hej Verden" : "Hello World";
  }

}

Notice how this @Bean method uses the InjectionPoint to get access to the annotation on the dependency injection target field (GreeterService.greeting). The Greeting annotation is some annotation I dreamt up – super simple (not even a Qualifier).

In addition to the annotations on the dependency injection target field (/method/constructor…) you can also get the class object of the containing class (GreeterService in the above example). Take a look at the JavaDoc for further information [1].

That’s it! Now, imagine what you can do with it😉 …

Relation to scope

I propose that InjectionPoint is specifically designed to work with prototype scoped beans. You may think that’s weird – but think about it this way:

  • If you use InjectionPoint in a singleton scoped @Bean method…
  • And if you have multiple places where the bean is injected…
  • Then how would Spring know which InjectionPoint to hand to you?

You know what? I actually tested that…and it turns out I was given the first InjectionPoint. To be completely honest: that surprised me. I actually would have expected an exception from the container. But no – I just got “the first” injection target encountered by the container. Imagine what use you have of that. My best guess is: no use at all.

CDI, by the way, only allows InjectionPoints when used with the dependent scope. Please take into account that CDI’s dependent scope and Spring’s prototype scope are roughly equivalent.

References

[1] Spring Frameworks JavaDoc on the InjectionPoint class:
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/InjectionPoint.html

[2] Spring Framework Reference Documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

 

Tagged with: ,
Posted in Spring

Java: Custom logger factory that automatically infers the class name

In this post I show how you can declare loggers like this:

public class MyService {
    private static final Logger LOG = MyLoggerFactory.getLogger();
}

There is no argument to the MyLoggerFactory::getLogger method. Contrast that to the normal way to declare a logger:

public class MyService {
    private static final Logger LOG = LoggerFactory.getLogger(MyService.class);
}

This is business as usual. But have you ever made that silly mistake where you copy/paste a class – and then, in the new class, forget to change the argument to that logger? It can be horribly misleading when reading log files afterwards.

The custom MyLoggerFactory::getLogger method is really super simple to implement: 3 lines of meat.

UPDATE: Alternative to the custom factory

On Reddit, while announcing this post, I was made aware of a simple alternative to the custom logger factory technique described in this post:

public class MyService {
    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.Lookup.lookupClass());
}

That technique uses a plain standard Java SE API to get the class name – see [1]. Personally I think this is a clever technique as well!

I guess it is a matter of personal preferences to decide which logger declaration you want to use. If you still find the logger factory compelling – then read on…

Implementation

I have prepared an example on GitHub – consult that to see the code in its entirety and full context. But here it goes, using SLF4j/Logback:

package com.never.that.copy.paste.mistake.again;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyLoggerFactory {

    public static Logger getLogger() {

        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

        String callersClassName = stackTrace[2].getClassName();

        return LoggerFactory.getLogger(callersClassName);
    }
}

3 lines of meat. The magic number 2 represents the class calling MyLoggerFactory::getLogger. The first positions in the stackTrace array represents the invocation to the Thread::getStackTrace method as well as this MyLoggerFactory::getLogger method itself.

I chose to name the method getLogger here, so that it aligns with the underlying logging framework SLF4j/Logback.

Please note, that no code here is specific to SLF4j/Logback: So go ahead and implement a corresponding factory for your own favorite logging framework.

The example on GitHub has a very limited JUnit test that shows it works as expected:

package com.never.that.copy.paste.mistake.again;

import org.junit.Test;
import org.slf4j.Logger;

import static org.junit.Assert.assertEquals;

public class MyLoggerFactoryTests {

    @Test
    public void getLogger_whenGivenNothing_thenReturnsLoggerWithCallersClassName() {

        // Given
        // ( a little bit of magic ... )

        // When
        Logger loggerOne = MyLoggerFactory.getLogger();
        Logger loggerTwo = LoggerTester.LOG;

        // Then
        assertEquals(MyLoggerFactoryTests.class.getName(), loggerOne.getName());
        assertEquals(LoggerTester.class.getName(), loggerTwo.getName());
    }

    private static class LoggerTester {
        private static final Logger LOG = MyLoggerFactory.getLogger();
    }

}

That’s all there is to it.

References

[1] Java SE’s MethodHandles API:
https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandles.Lookup.html#lookupClass&#8211;

Tagged with: ,
Posted in Java SE