Wednesday, October 22, 2014

ConEmu - Windows console emulator with tabs

After switching to Git some time ago, I started working more and more with Git Bash on Windows. Git Bash is pretty cool as it provides (apart from Git) Bash supported with basic Unix tools including curl or ssh. Git Bash in Windows has some limitation though including limited customization options and lack of good copy & paste options supported with keyboard shortcuts. Fortunately, there is ConEmu that not only fills that gap but adds various features that make working with console applications more productive and more enjoyable for me.

Friday, October 17, 2014

Spring Boot / Java 8 / Tomcat 8 on Openshift with DIY

DIY cartridge is an experimental cartridge that provides a way to test unsupported languages on OpenShift. It provides a minimal, free-form scaffolding which leaves all details of the cartridge to the application developer. This blog post illustrates the use of Spring Boot / Java 8 / Tomcat 8 application with PostgreSQL service bound to it.

Wednesday, October 8, 2014

Spring Boot and Spring Data REST - exposing repositories over REST

Exposing Spring Data repositories over REST is pretty easy with Spring Boot and Spring Data REST. With minimal code one can create REST representations of JPA entities that follow the HATEOAS principle. I decided to re-use Spring PetClinic’s JPA entities (business layer) as the foundation for this article.

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