Wednesday, September 17, 2014

Using @ConfigurationProperties in Spring Boot

In my latest blog post I described shortly how one can configure mail in Spring Boot application. To inject properties into the configuration I used Spring’s @Value annotation. But Spring Boot provides an alternative method of working with properties that allows strongly typed beans to govern and validate the configuration of your application. In this post I will demonstrate how to utilize @ConfigurationProperties while configuring the application.

Tuesday, September 16, 2014

Testing mail code in Spring Boot application

Whilst building a Spring Boot application you may encounter a need of adding a mail configuration. Actually, configuring the mail in Spring Boot does not differ much from configuring it in Spring Bootless application. But how to test that mail configuration and submission is working fine? Let’s have a look.

Tuesday, August 12, 2014

Validation groups in Spring MVC

All constraints in Bean Validation may be added to one or more groups via groups attribute. This allows you to restrict the set of constraints applied during validation. It can be handy in cases where some groups should be validated before others like e.g. in wizards. As of Spring MVC 3.1, automatic validation utilizing validation groups is possible with org.springframework.validation.annotation.Validated annotation. In this article I will use simple Spring MVC application to demonstrate how easily you can use validation groups to validate Spring’s MVC model attributes.

Form

Let’s start with the form class that will be validated in steps. Firstly, we define interfaces that represents constraint groups:

public class Account implements PasswordAware {

    interface ValidationStepOne {
        // validation group marker interface
    }

    interface ValidationStepTwo {
        // validation group marker interface
    }
}

Validation contraints

Next we assign constraint to groups. Remember, if you don’t provide groups the default one will be used. Please also note @SamePasswords, @StrongPassword - custom constraints, that must define groups attribute:

@SamePasswords(groups = {Account.ValidationStepTwo.class})
public class Account implements PasswordAware {

    @NotBlank(groups = {ValidationStepOne.class})
    private String username;

    @Email(groups = {ValidationStepOne.class})
    @NotBlank(groups = {ValidationStepOne.class})
    private String email;

    @NotBlank(groups = {ValidationStepTwo.class})
    @StrongPassword(groups = {ValidationStepTwo.class})
    private String password;

    @NotBlank(groups = {ValidationStepTwo.class})
    private String confirmedPassword;

    // getters and setters
}

Wizard

Having the Account, we can create a 3-step wizard @Controller that will let users create an account. In first step we will let Spring validate constraint in ValidationStepOne group:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "stepOne")
    public String stepOne(Model model) {
        model.addAttribute("account", new Account());
        return VIEW_STEP_ONE;
    }

    @RequestMapping(value = "stepOne", method = RequestMethod.POST)
    public String stepOne(@Validated(Account.ValidationStepOne.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_ONE;
        }
        return "redirect:stepTwo";
    }
}

To trigger validation with groups I used @Validated annotation. This annotation takes var-arg argument with groups’ types. The code @Validated(ValidationStepOne.class) triggers validation of constraint in ValidationStepOne group.

In the next step we will let Spring validate constraint in ValidationStepTwo group:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "stepTwo")
    public String stepTwo() {
        return VIEW_STEP_TWO;
    }

    @RequestMapping(value = "stepTwo", method = RequestMethod.POST)
    public String stepTwo(@Validated(Account.ValidationStepTwo.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_TWO;
        }
        return "redirect:summary";
    }
}

In the summary step we will confirm entered data and we will let Spring validate constraint of both groups:

@Controller
@RequestMapping("validationgroups")
@SessionAttributes("account")
public class AccountController {

    @RequestMapping(value = "summary")
    public String summary() {
        return VIEW_SUMMARY;
    }

    @RequestMapping(value = "confirm")
    public String confirm(@Validated({Account.ValidationStepOne.class, Account.ValidationStepTwo.class}) Account account, Errors errors, SessionStatus status) {
        status.setComplete();
        if (errors.hasErrors()) {
            // did not pass full validation
        }
        return "redirect:start";
    }
}

Prior to Spring 3.1 you could trigger the validation manually. I described this in one of my previous posts: http://blog.codeleak.pl/2011/03/how-to-jsr303-validation-groups-in.html

Note: If you want to use validation groups without Spring, you need to pass groups to javax.validation.Validator#validate():

Validation groups without Spring

Validator validator = Validation
        .buildDefaultValidatorFactory().getValidator();
Account account = new Account();

// validate with first group
Set<ConstraintViolation<Account>> constraintViolations =
        validator.validate(account, Account.ValidationStepOne.class);
assertThat(constraintViolations).hasSize(2);

// validate with both groups
Set<ConstraintViolation<Account>> constraintViolations =
        validator.validate(account, Account.ValidationStepOne.class, Account.ValidationStepTwo.class);
assertThat(constraintViolations).hasSize(4);

This is also the easiest way to test validations:

public class AccountValidationTest {

    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Test
    public void shouldHaveFourConstraintViolationsWhileValidatingBothGroups() {
        Account account = new Account();
        Set<ConstraintViolation<Account>> constraintViolations = validator.validate(
                account, Account.ValidationStepOne.class, Account.ValidationStepTwo.class
        );
        assertThat(constraintViolations).hasSize(4);
    }

    @Test
    public void shouldHaveTwoConstraintViolationsWhileStepOne() {
        Account account = new Account();
        Set<ConstraintViolation<Account>> constraintViolations = validator.validate(
                account, Account.ValidationStepOne.class
        );
        assertThat(constraintViolations).hasSize(2);

    }
}

Testing validation with Spring Test

Testing validation with Spring Test offers more sophisticated way of testing if validation/binding failed. For the examples, have a look at my other blog post: Spring MVC Integration Testing: Assert the given model attribute(s) have global errors

The source code for this article can be found here: https://github.com/kolorobot/spring-mvc-beanvalidation11-demo

Tuesday, August 5, 2014

Spring MVC Integration Testing: Assert the given model attribute(s) have global errors

In order to report a global error in Spring MVC using Bean Validation we can create a custom class level constraint annotation. Global errors are not associated with any specific fields in the validated bean. In this article I will show how to write a test with Spring Test that verifies if the given model attribute has global validation errors.

Custom (Class Level) Constraint

For the sake of this article, I created a relatively simple class level constraint called SamePassword, validated by SamePasswordValidator:

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = SamePasswordsValidator.class)
@Documented
public @interface SamePasswords {
    String message() default "passwords do not match";
    Class<?>[] groups() default {}; 
    Class<? extends Payload>[] payload() default {};
}

As you can see below, the validator is really simple:

public class SamePasswordsValidator implements ConstraintValidator<SamePasswords, PasswordForm> {

    @Override
    public void initialize(SamePasswords constraintAnnotation) {}

    @Override
    public boolean isValid(PasswordForm value, ConstraintValidatorContext context) {
        if(value.getConfirmedPassword() == null) {
            return true;
        }
        return value.getConfirmedPassword()
                    .equals(value.getPassword());
    }
}

The PasswordForm is just a POJO with some constraint annotations, inclduing the once I have just created:

@SamePasswords
public class PasswordForm {
    @NotBlank
    private String password;
    @NotBlank
    private String confirmedPassword;

    // getters and setters omitted for redability

}

@Controller

The controller has two methods: to display the form and to handle the submission of the form:

@Controller
@RequestMapping("globalerrors")
public class PasswordController {

    @RequestMapping(value = "password")
    public String password(Model model) {
        model.addAttribute(new PasswordForm());
        return "globalerrors/password";
    }

    @RequestMapping(value = "password", method = RequestMethod.POST)
    public String stepTwo(@Valid PasswordForm passwordForm, Errors errors) {
        if (errors.hasErrors()) {
            return "globalerrors/password";
        }
        return "redirect:password";
    }
}

When the password validation fails, a global error is registered in a BindingResult (Errors in the above example) object. We could then display this error on top of the form in a HTML page for example. In Thymeleaf this would be:

<div th:if="${#fields.hasGlobalErrors()}">
  <p th:each="err : ${#fields.globalErrors()}" th:text="${err}">...</p>
</div>

Integration Testing with Spring Test

Let’s setup an integration test:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class AccountValidationIntegrationTest {

    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
}

The first test verifies that sending a form with empty password and confirmedPassword fails:

    @Test
    public void failsWhenEmptyPasswordsGiven() throws Exception {
        this.mockMvc.perform(post("/globalerrors/password")
                .param("password", "").param("confirmedPassword", ""))
                .andExpect(
                    model().attributeHasFieldErrors(
                        "passwordForm", "password", "confirmedPassword"
                    )
                )
                .andExpect(status().isOk())
                .andExpect(view().name("globalerrors/password"));
    }

In the above example, the test verifies if there are field errors for both password and confirmedPassword fields.

Similarly, I would like to verify that when given passwords do not match, I get a specific, global error. So I would expect something like this: .andExpect(model().hasGlobalError("passwordForm", "passwords do not match")). Unfortunately, ModelResultMatchers returned by MockMvcResultMatchers#model() does not provide methods to assert the given model attribute(s) have global errors

Since it is not there, I created my own matcher that extends from ModelResultMatchers. The Java 8 version of the code is below:

public class GlobalErrorsMatchers extends ModelResultMatchers {

    private GlobalErrorsMatchers() {
    }

    public static GlobalErrorsMatchers globalErrors() {
        return new GlobalErrorsMatchers();
    }

    public ResultMatcher hasGlobalError(String attribute, String expectedMessage) {
        return result -> {
            BindingResult bindingResult = getBindingResult(
                result.getModelAndView(), attribute
            );
            bindingResult.getGlobalErrors()
                .stream()
                .filter(oe -> attribute.equals(oe.getObjectName()))
                .forEach(oe -> assertEquals(
                    "Expected default message", expectedMessage, oe.getDefaultMessage())
                );
        };
    }

    private BindingResult getBindingResult(ModelAndView mav, String name) {
        BindingResult result = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + name);
        assertTrue(
            "No BindingResult for attribute: " + name, result != null
        );
        assertTrue(
            "No global errors for attribute: " + name, result.getGlobalErrorCount() > 0
        );
        return result;
    }
}

With the above addition I am now able to verify global validation errors like here below:


import static pl.codeleak.demo.globalerrors.GlobalErrorsMatchers.globalErrors;

@Test
public void failsWithGlobalErrorWhenDifferentPasswordsGiven() throws Exception {
    this.mockMvc.perform(post("/globalerrors/password")
            .param("password", "test").param("confirmedPassword", "other"))
            .andExpect(globalErrors().hasGlobalError(
                "passwordForm", "passwords do not match")
            )
            .andExpect(status().isOk())
            .andExpect(view().name("globalerrors/password"));
}

As you can see extending Spring Test’s matchers and providing you own is relatively easy and can be used to improve validation verification in an integration test.

Resources

The source code for this article can be found here: https://github.com/kolorobot/spring-mvc-beanvalidation11-demo

Monday, July 28, 2014

Spring 4.1 and Java 8: java.util.Optional as a @RequestParam, @RequestHeader and @MatrixVariable in Spring MVC

As of Spring 4.1 Java 8’s java.util.Optional, a container object which may or may not contain a non-null value, is supported with @RequestParam, @RequestHeader and @MatrixVariable. While using Java 8’s java.util.Optional you make sure your parameters are never null.

Monday, July 7, 2014

JUnit: testing exception with Java 8 and Lambda Expressions

In JUnit there are many ways of testing exceptions in test code, including try-catch idiom, JUnit @Rule, with catch-exception library. As of Java 8 we have another way of dealing with exceptions: with lambda expressions. In this short blog post I will demonstrate a simple example how one can utilize the power of Java 8 and lambda expressions to test exceptions in JUnit.

Wednesday, July 2, 2014

Spring 4: CGLIB-based proxy classes with no default constructor

In Spring, if the class of a target object that is to be proxied doesn’t implement any interfaces, then a CGLIB-based proxy will be created. Prior to Spring 4, CGLIB-based proxy classes require a default constructor. And this is not the limitation of CGLIB library, but Spring itself. Fortunately, as of Spring 4 this is no longer an issue. CGLIB-based proxy classes no longer require a default constructor. How can this impact your code? Let’s see.

One of the idioms of dependency injection is constructor injection. It can be generally used when the injected dependencies are required and must not change after the object is initiated. In this article I am not going to discuss why and when you should use constructor dependency injection. I assume you use this idiom in your code or you consider using it. If you are interested in learning more, see the resources section in the bottom of this article.

Contructor injection with no-proxied beans

Having the following collaborator:


package pl.codeleak.services;

import org.springframework.stereotype.Service;

@Service
public class Collaborator {
    public String collaborate() {
        return "Collaborating";
    }
}

we can easily inject it via constructor:

package pl.codeleak.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SomeService {

    private final Collaborator collaborator;

    @Autowired
    public SomeService(Collaborator collaborator) {
        this.collaborator = collaborator;
    }

    public String businessMethod() {
        return collaborator.collaborate();
    }

}

You may notice the both Collaborator and the Service has no interfaces, but they are no proxy candidates. So this code will work perfectly fine with Spring 3 and Spring 4:

package pl.codeleak.services;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import pl.codeleak.Configuration;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Configuration.class)
public class WiringTests {

    @Autowired
    private SomeService someService;

    @Autowired
    private Collaborator collaborator;

    @Test
    public void hasValidDependencies() {
        assertThat(someService)
                .isNotNull()
                .isExactlyInstanceOf(SomeService.class);

        assertThat(collaborator)
                .isNotNull()
                .isExactlyInstanceOf(Collaborator.class);

        assertThat(someService.businessMethod())
                .isEqualTo("Collaborating");
    }
}

Contructor injection with proxied beans

In many cases your beans need to be decorated with an AOP proxy at runtime, e.g when you want to use declarative transactions with @Transactional annotation. To visualize this, I created an aspect that will advice all methods in SomeService. With the below aspect defined, SomeService becomes a candidate for proxying:

package pl.codeleak.aspects;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DummyAspect {

    @Before("within(pl.codeleak.services.SomeService)")
    public void before() {
        // do nothing
    }

}

When I re-run the test with Spring 3.2.9, I get the following exception:

Could not generate CGLIB subclass of class [class pl.codeleak.services.SomeService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given

This can be simply fixed by providing a default, no argument, constructor to SomeService, but this is not what I want to do - as I would also need to make dependencies non-final.

Another solution would be to provide an interface for SomeService. But again, there are many situation when you don’t need to create interfaces.

Updating to Spring 4 solves the problem immediately. As documentation states:

CGLIB-based proxy classes no longer require a default constructor. Support is provided via the objenesis library which is repackaged inline and distributed as part of the Spring Framework. With this strategy, no constructor at all is being invoked for proxy instances anymore.

The test I created will fail, but it visualizes that CGLIB proxy was created for SomeService:

java.lang.AssertionError: 
Expecting:
 <pl.codeleak.services.SomeService@6a84a97d>
to be exactly an instance of:
 <pl.codeleak.services.SomeService>
but was an instance of:
 <pl.codeleak.services.SomeService$$EnhancerBySpringCGLIB$$55c3343b>

After removing the first assertion from the test, it will run just perfectly fine.

Resources

In case you need read more about constructor dependency injection, have a look at this great article by Petri Kainulainen: http://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection.

Core Container Improvements in Spring 4: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/new-in-4.0.html#_core_container_improvements

You may also be interested in reading my other articles about Spring: Spring 4: @DateTimeFormat with Java 8 Date-Time API and Better error messages with Bean Validation 1.1 in Spring MVC application