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

Spring Boot: Show all logging events for one Web request only

In this post I show how you for a single Web request can make your Spring Boot application dump all log statements on all categories (TRACE, DEBUG, INFO, WARN, ERROR). Everything – but only for the specific Web request that you care about. I show the technique using Spring Boot 1.4. 

Here’s an example. Imagine a call to:

http://localhost:8080/greetings/duke?trace=on

The trace query parameter is completely unknown to the actual GreetingController. But it instructs your application to log everything related to that request:

Screen Shot 2016-08-24 at 20.50.01
With this amount of information you can go ahead and troubleshoot those hard to understand production issues! Compare that to what you will get without the trace support:

Screen Shot 2016-08-24 at 20.52.04
The best thing: once you have implemented support for the trace query parameter, you can use it on any Web request to your application: Servlets, JSP’s, SOAP endpoints, REST endpoints and so on. In fact: they don’t even know about it.

Spring Boot implementation

I have prepared a GitHub example – consult that to see all source code in its entirety and full context. 

Here is what you need to do:

  1. Create a ThreadLocal(ish) object that knows when everything should be logged
  2. Create a Web filter that manages this ThreadLocal(ish) object
  3. Hook into the logging provider so that it can use the ThreadLocal(ish) object to decide wether or not to log a logging event

Spring Boot’s default logging provider is Logback. So I have used that in this example when implementing step three. Here it goes.

Step 1 of 3: Class ThreadLoggingSupport

public class ThreadLoggingSupport {

    private static final Map<Long, Boolean> THREAD_TO_ENABLED = new HashMap<>();

    public static void logEverything(boolean enabled) {
        THREAD_TO_ENABLED.put(Thread.currentThread().getId(), enabled);
    }

    public static boolean shouldLogEverything() {
        return Optional.ofNullable(THREAD_TO_ENABLED.get(Thread.currentThread().getId()))
                .orElse(false);
    }

    public static void cleanup() {
        THREAD_TO_ENABLED.remove(Thread.currentThread().getId());
    }
}

The purpose of this class is to allow code in the Web layer (next step) to communicate with the logging system (step 3).

(I deliberately chose not to use a ThreadLocal here: since the use of it in step 3 would have made it bind to all threads that uses Logback – and not only the Web container threads.)

Step 2 of 3: Class ThreadLoggingFilterBean

@Component
public class ThreadLoggingFilterBean extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            boolean logEverythingForThisRequest = "on".equalsIgnoreCase(request.getParameter("trace"));
            ThreadLoggingSupport.logEverything(logEverythingForThisRequest);
            chain.doFilter(request, response);
        } finally {
            ThreadLoggingSupport.cleanup();
        }
    }

}

This is an ordinary Spring GenericFilterBean. All Web requests goes through this filter. Notice how it pulls out the trace query parameter value. If it has the value on then it will tell the log system to go nuts – logging everything it receives.

Step 3 of 3: Class ThreadLoggingInitializer

@Component
public class ThreadLoggingInitializer {

    private static org.slf4j.Logger LOG = LoggerFactory.getLogger(ThreadLoggingInitializer.class);

    @EventListener
    public void handleContextRefresh(ContextRefreshedEvent event) {
        LoggerContext loggerContext = ((Logger) LoggerFactory.getLogger("")).getLoggerContext();
        loggerContext.addTurboFilter(new TurboFilter() {
            @Override
            public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
                return (ThreadLoggingSupport.shouldLogEverything()) ? FilterReply.ACCEPT : FilterReply.NEUTRAL;
            }
        });
        LOG.info("ThreadLogging support initialized");
    }
}

This is where we enter Logback specifics: We register a global log filter (a TurboFilter) that knows when to:

  • Force the logging of a specific logging event, or
  • Ignore the specific logging event

All logging events go through this filter – so it is important to avoid putting expensive code here.

Here we simply check the ThreadLocal(ish) state and use that to decide wether the current logging event should be logged or ignored. Ignoring it here means that this filter wont interfere in the decision. For more information about Logback and its filter support, refer to the online manual [1].

Closing remarks

Here I used Web requests as an example. But you can easily apply this technique to incoming JMS messages, scheduled jobs and so on.

Also, the technique was explained using Spring Boot. But you can easily apply it to other Web frameworks as well.

Be creative – bend that spoon.

References

[1] Logback – Chapter 7: Filters
http://logback.qos.ch/manual/filters.html

Tagged with: ,
Posted in Spring

Spring Boot: Sessions actuator endpoint

This post shows how you can implement a custom Spring Boot Actuator endpoint that prints information about all active HttpSessions:

Screen Shot 2016-08-22 at 22.23.45

HttpSession meta data is prefixed with @ signs: id, creation time and last accessed time. The other values are a raw dump of all the HttpSession attributes.

You can use this endpoint during development to inspect active sessions. Or you can use it on production systems when troubleshooting customer issues. Whatever you choose, make sure that you secure such an endpoint appropriately: You could expose some very sensitive data.

For an introduction to custom Spring Boot Actuator endpoints, refer to my previous post: Spring Boot: Introduce your own insight endpoints.

Implementation

I have prepared a GitHub example based on Spring Boot 1.4 – find it here. Consult that to see the code in it’s entirety and full context. Here’s the main principles that makes this possible:

  • Create a class to act as a registry of all active HttpSessions
  • Create an HttpSession listener that registers and de-registers the HttpSessions
  • Create a Spring Boot Actuator endpoint that dumps the internal state of all of the HttpSessions

Step 1 of 3: Class SessionRegistry

@Service
public class SessionRegistry {

    private final Map<String, HttpSession> httpSessionMap = new ConcurrentSkipListMap<>();

    public void addSession(HttpSession httpSession) {
        this.httpSessionMap.put(httpSession.getId(), httpSession);
    }

    public void removeSession(HttpSession httpSession) {
        this.httpSessionMap.remove(httpSession.getId());
    }

    public List<HttpSession> getSessions() {
        return new ArrayList<>(httpSessionMap.values());
    }
}

The httpSessionMap is a concurrent version of Map: to avoid ConcurrentModificationExceptions.

Step 2 of 3: Class SessionListener

@Component
public class SessionListener implements HttpSessionListener {

    @Autowired
    private SessionRegistry sessionRegistry;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        sessionRegistry.addSession(se.getSession());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        sessionRegistry.removeSession(se.getSession());
    }
}

This is a Spring’ified version of a traditional Servlet container component: HttpSessionListener. This class maintains the registry.

Step 3 of 3: Class SessionActuatorEndpoint

This is the interesting part – where we create a Spring Boot Actuator endpoint:

@Component
public class SessionsActuatorEndpoint extends AbstractMvcEndpoint {

    @Autowired
    private SessionRegistry sessionRegistry;

    public SessionsActuatorEndpoint() {
        super("/sessions", true/*sensitive*/);
    }

    @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public SessionStateActuatorEndpointResponse listActiveSessions() {
        return new SessionStateActuatorEndpointResponse("Active HTTP sessions", sessionRegistry.getSessions());
    }

    @JsonPropertyOrder({"info", "numberOfActiveSessions", "sessions"})
    public static class SessionStateActuatorEndpointResponse {

        @JsonProperty
        private String info;

        @JsonProperty
        private int numberOfActiveSessions;

        @JsonProperty
        private List<Map<String, String>> sessions;

        public SessionStateActuatorEndpointResponse(String info, List<HttpSession> httpSessions) {
            this.info = info;
            this.numberOfActiveSessions = httpSessions.size();
            this.sessions = httpSessions.stream()
                    .map(this::getSessionState)
                    .collect(Collectors.toList());
        }

        private Map<String, String> getSessionState(HttpSession httpSession) {
            Map<String, String> sessionState = new LinkedHashMap<>();
            sessionState.put("@session_id", httpSession.getId());
            sessionState.put("@session_creation_time", formatDateTime(httpSession.getCreationTime()));
            sessionState.put("@session_last_accessed_time", formatDateTime(httpSession.getLastAccessedTime()));
            for (Enumeration<String> attributeNames = httpSession.getAttributeNames(); attributeNames.hasMoreElements(); ) {
                String attributeName = attributeNames.nextElement();
                Object attributeValue = httpSession.getAttribute(attributeName);
                sessionState.put(attributeName, attributeValue instanceof String || attributeValue instanceof Number ?
                        attributeValue.toString() : ReflectionToStringBuilder.toString(attributeValue));
            }
            return sessionState;
        }

        private String formatDateTime(long epoch) {
            Instant instant = Instant.ofEpochMilli(epoch);
            ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
            return zonedDataTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        }
    }

}

The thing that makes this a Spring Boot Actuator endpoint is that it declares AbstractMvcEndpoint as its superclass. Also take note of the constructor: this is where you register the path at which this endpoint can be found (‘/sessions‘).

The inner class SessionStateActuatorEndpointResponse represents the JSON response structure. I’ve selected some meta data that I find interesting and added that in the output – prefixed with ‘@’ characters. Other than that, it simply dumps all HttpSession attributes. Notice that it uses commons ReflectionToStringBuilder for object structures other than Strings and Numbers.

 

Tagged with:
Posted in Spring