package net.petrikainulainen.springdata.jpa.web;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
import net.petrikainulainen.springdata.jpa.web.error.RestErrorHandler;
import org.springframework.context.MessageSource;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.data.web.SortHandlerMethodArgumentResolver;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Locale;
/**
* This factory class provides methods that can be used to create objects that are useful
* when we are writing unit tests for our controller methods by using the Spring MVC Test
* framework.
*
* @author Petri Kainulainen
*/
final class WebTestConfig {
private WebTestConfig() {}
/**
* Configures a {@link org.springframework.web.servlet.LocaleResolver} that always returns the
* configured {@link java.util.Locale}.
*
* @return
*/
static LocaleResolver fixedLocaleResolver(Locale fixedLocale) {
return new FixedLocaleResolver(fixedLocale);
}
/**
* This method creates a custom {@link org.springframework.http.converter.HttpMessageConverter} which ensures that:
*
* <ul>
* <li>Null values are ignored.</li>
* <li>
* The new Java 8 date objects are serialized in standard
* <a href="http://en.wikipedia.org/wiki/ISO_8601" target="_blank">ISO-8601</a> string representation.
* </li>
* </ul>
*
* @return
*/
static MappingJackson2HttpMessageConverter jacksonDateTimeConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.registerModule(new JSR310Module());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
return converter;
}
/**
* This method ensures that the {@link RestErrorHandler} class
* is used to handle the exceptions thrown by the tested controller. I borrowed this idea from
* <a href="http://stackoverflow.com/a/27195332/313554" target="_blank">this StackOverflow answer</a>.
*
* @return an error handler component that delegates relevant exceptions forward to the {@link RestErrorHandler} class.
*/
static ExceptionHandlerExceptionResolver restErrorHandler(MessageSource messageSource) {
final ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
@Override
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(final HandlerMethod handlerMethod,
final Exception exception) {
Method method = new ExceptionHandlerMethodResolver(RestErrorHandler.class).resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(new RestErrorHandler(messageSource), method);
}
return super.getExceptionHandlerMethod(handlerMethod, exception);
}
};
exceptionResolver.setMessageConverters(Arrays.asList(jacksonDateTimeConverter()));
exceptionResolver.afterPropertiesSet();
return exceptionResolver;
}
/**
* This method returns a {@link org.springframework.web.method.support.HandlerMethodArgumentResolver} that can
* construct {@link org.springframework.data.domain.Sort} objects by using the request params of the
* incoming request.
* @return
*/
static SortHandlerMethodArgumentResolver sortArgumentResolver() {
return new SortHandlerMethodArgumentResolver();
}
/**
* This method returns a {@link org.springframework.web.method.support.HandlerMethodArgumentResolver} that can
* construct {@link org.springframework.data.domain.Pageable} objects by using the request params of the
* incoming request.
* @return
*/
static PageableHandlerMethodArgumentResolver pageRequestArgumentResolver() {
return new PageableHandlerMethodArgumentResolver(sortArgumentResolver());
}
/**
* This method creates a validator object that adds support for bean validation API 1.0 and 1.1.
*
* @return The created validator object.
*/
static LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}