Package org.springframework.web.servlet.config.annotation

Source Code of org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupportExtensionTests$TestPathHelper

/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.web.servlet.config.annotation;

import java.util.Arrays;
import java.util.List;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;

import org.springframework.beans.DirectFieldAccessor;
import org.springframework.core.Ordered;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.AntPathMatcher;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.Errors;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptorAdapter;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.ViewResolverComposite;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import org.springframework.web.util.UrlPathHelper;

import static org.junit.Assert.*;

/**
* A test fixture with a sub-class of {@link WebMvcConfigurationSupport} that also
* implements the various {@link WebMvcConfigurer} extension points.
*
* The former doesn't implement the latter but the two must have compatible
* callback method signatures to support moving from simple to advanced
* configuration -- i.e. dropping @EnableWebMvc + WebMvcConfigurer and extending
* directly from WebMvcConfigurationSupport.
*
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
*/
public class WebMvcConfigurationSupportExtensionTests {

  private TestWebMvcConfigurationSupport config;

  private StaticWebApplicationContext context;


  @Before
  public void setUp() {
    this.context = new StaticWebApplicationContext();
    this.context.setServletContext(new MockServletContext(new FileSystemResourceLoader()));
    this.context.registerSingleton("controller", TestController.class);

    this.config = new TestWebMvcConfigurationSupport();
    this.config.setApplicationContext(this.context);
    this.config.setServletContext(this.context.getServletContext());
  }

  @Test
  public void handlerMappings() throws Exception {
    RequestMappingHandlerMapping rmHandlerMapping = this.config.requestMappingHandlerMapping();
    rmHandlerMapping.setApplicationContext(this.context);
    rmHandlerMapping.afterPropertiesSet();
    assertEquals(TestPathHelper.class, rmHandlerMapping.getUrlPathHelper().getClass());
    assertEquals(TestPathMatcher.class, rmHandlerMapping.getPathMatcher().getClass());
    HandlerExecutionChain chain = rmHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/"));
    assertNotNull(chain.getInterceptors());
    assertEquals(3, chain.getInterceptors().length);
    assertEquals(LocaleChangeInterceptor.class, chain.getInterceptors()[0].getClass());
    assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[1].getClass());
    assertEquals(ResourceUrlProviderExposingInterceptor.class, chain.getInterceptors()[2].getClass());

    AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) this.config.viewControllerHandlerMapping();
    handlerMapping.setApplicationContext(this.context);
    assertNotNull(handlerMapping);
    assertEquals(1, handlerMapping.getOrder());
    assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass());
    assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass());
    chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path"));
    assertNotNull(chain.getHandler());
    chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/bad"));
    assertNotNull(chain.getHandler());
    chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/old"));
    assertNotNull(chain.getHandler());

    handlerMapping = (AbstractHandlerMapping) this.config.resourceHandlerMapping();
    handlerMapping.setApplicationContext(this.context);
    assertNotNull(handlerMapping);
    assertEquals(Integer.MAX_VALUE - 1, handlerMapping.getOrder());
    assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass());
    assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass());
    chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif"));
    assertNotNull(chain.getHandler());
    assertEquals(Arrays.toString(chain.getInterceptors()), 2, chain.getInterceptors().length);
    // PathExposingHandlerInterceptor at chain.getInterceptors()[0]
    assertEquals(ResourceUrlProviderExposingInterceptor.class, chain.getInterceptors()[1].getClass());

    handlerMapping = (AbstractHandlerMapping) this.config.defaultServletHandlerMapping();
    handlerMapping.setApplicationContext(this.context);
    assertNotNull(handlerMapping);
    assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
    chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath"));
    assertNotNull(chain.getHandler());
  }

  @SuppressWarnings("unchecked")
  @Test
  public void requestMappingHandlerAdapter() throws Exception {
    RequestMappingHandlerAdapter adapter = this.config.requestMappingHandlerAdapter();

    // ConversionService
    String actual = this.config.mvcConversionService().convert(new TestBean(), String.class);
    assertEquals("converted", actual);

    // Message converters
    assertEquals(1, adapter.getMessageConverters().size());
    assertEquals(MappingJackson2HttpMessageConverter.class, adapter.getMessageConverters().get(0).getClass());
    ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter)adapter.getMessageConverters().get(0)).getObjectMapper();
    assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
    assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
    assertFalse(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));

    DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(adapter);

    // Custom argument resolvers and return value handlers
    List<HandlerMethodArgumentResolver> argResolvers =
      (List<HandlerMethodArgumentResolver>) fieldAccessor.getPropertyValue("customArgumentResolvers");
    assertEquals(1, argResolvers.size());

    List<HandlerMethodReturnValueHandler> handlers =
      (List<HandlerMethodReturnValueHandler>) fieldAccessor.getPropertyValue("customReturnValueHandlers");
    assertEquals(1, handlers.size());

    // Async support options
    assertEquals(ConcurrentTaskExecutor.class, fieldAccessor.getPropertyValue("taskExecutor").getClass());
    assertEquals(2500L, fieldAccessor.getPropertyValue("asyncRequestTimeout"));

    CallableProcessingInterceptor[] callableInterceptors =
        (CallableProcessingInterceptor[]) fieldAccessor.getPropertyValue("callableInterceptors");
    assertEquals(1, callableInterceptors.length);

    DeferredResultProcessingInterceptor[] deferredResultInterceptors =
        (DeferredResultProcessingInterceptor[]) fieldAccessor.getPropertyValue("deferredResultInterceptors");
    assertEquals(1, deferredResultInterceptors.length);

    assertEquals(false, fieldAccessor.getPropertyValue("ignoreDefaultModelOnRedirect"));
  }

  @Test
  public void webBindingInitializer() throws Exception {
    RequestMappingHandlerAdapter adapter = this.config.requestMappingHandlerAdapter();

    ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
    assertNotNull(initializer);

    BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(null, "");
    initializer.getValidator().validate(null, bindingResult);
    assertEquals("invalid", bindingResult.getAllErrors().get(0).getCode());

    String[] codes = initializer.getMessageCodesResolver().resolveMessageCodes("invalid", null);
    assertEquals("custom.invalid", codes[0]);
  }

  @Test
  public void contentNegotiation() throws Exception {
    MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.json");
    NativeWebRequest webRequest = new ServletWebRequest(request);

    ContentNegotiationManager manager = this.config.requestMappingHandlerMapping().getContentNegotiationManager();
    assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(webRequest));

    request.setRequestURI("/foo.xml");
    assertEquals(Arrays.asList(MediaType.APPLICATION_XML), manager.resolveMediaTypes(webRequest));

    request.setRequestURI("/foo.rss");
    assertEquals(Arrays.asList(MediaType.valueOf("application/rss+xml")), manager.resolveMediaTypes(webRequest));

    request.setRequestURI("/foo.atom");
    assertEquals(Arrays.asList(MediaType.APPLICATION_ATOM_XML), manager.resolveMediaTypes(webRequest));

    request.setRequestURI("/foo");
    request.setParameter("f", "json");
    assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(webRequest));
  }

  @Test
  public void exceptionResolvers() throws Exception {
    HandlerExceptionResolver exceptionResolver = this.config.handlerExceptionResolver();
    assertEquals(1, ((HandlerExceptionResolverComposite) exceptionResolver).getExceptionResolvers().size());
  }

  @SuppressWarnings("unchecked")
  @Test
  public void viewResolvers() throws Exception {
    ViewResolverComposite viewResolver = (ViewResolverComposite) this.config.mvcViewResolver();
    assertEquals(Ordered.HIGHEST_PRECEDENCE, viewResolver.getOrder());
    List<ViewResolver> viewResolvers = viewResolver.getViewResolvers();

    DirectFieldAccessor accessor = new DirectFieldAccessor(viewResolvers.get(0));
    assertEquals(1, viewResolvers.size());
    assertEquals(ContentNegotiatingViewResolver.class, viewResolvers.get(0).getClass());
    assertFalse((Boolean) accessor.getPropertyValue("useNotAcceptableStatusCode"));
    assertNotNull(accessor.getPropertyValue("contentNegotiationManager"));

    List<View> defaultViews = (List<View>)accessor.getPropertyValue("defaultViews");
    assertNotNull(defaultViews);
    assertEquals(1, defaultViews.size());
    assertEquals(MappingJackson2JsonView.class, defaultViews.get(0).getClass());

    viewResolvers = (List<ViewResolver>)accessor.getPropertyValue("viewResolvers");
    assertNotNull(viewResolvers);
    assertEquals(1, viewResolvers.size());
    assertEquals(InternalResourceViewResolver.class, viewResolvers.get(0).getClass());
    accessor = new DirectFieldAccessor(viewResolvers.get(0));
    assertEquals("/", accessor.getPropertyValue("prefix"));
    assertEquals(".jsp", accessor.getPropertyValue("suffix"));
  }


  @Controller
  private static class TestController {

    @RequestMapping("/")
    public void handle() {
    }
  }

  /**
   * Since WebMvcConfigurationSupport does not implement WebMvcConfigurer, the purpose
   * of this test class is also to ensure the two are in sync with each other. Effectively
   * that ensures that application config classes that use the combo {@code @EnableWebMvc}
   * plus WebMvcConfigurer can switch to extending WebMvcConfigurationSupport directly for
   * more advanced configuration needs.
   */
  private class TestWebMvcConfigurationSupport extends WebMvcConfigurationSupport implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
      registry.addConverter(new Converter<TestBean, String>() {
        @Override
        public String convert(TestBean source) {
          return "converted";
        }
      });
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
      converters.add(new MappingJackson2HttpMessageConverter());
    }

    @Override
    public Validator getValidator() {
      return new Validator() {
        @Override
        public void validate(Object target, Errors errors) {
          errors.reject("invalid");
        }
        @Override
        public boolean supports(Class<?> clazz) {
          return true;
        }
      };
    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
      configurer.favorParameter(true).parameterName("f");
    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
      configurer.setDefaultTimeout(2500).setTaskExecutor(new ConcurrentTaskExecutor())
        .registerCallableInterceptors(new CallableProcessingInterceptorAdapter() { })
        .registerDeferredResultInterceptors(new DeferredResultProcessingInterceptorAdapter() {});
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
      argumentResolvers.add(new ModelAttributeMethodProcessor(true));
    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
      returnValueHandlers.add(new ModelAttributeMethodProcessor(true));
    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
      exceptionResolvers.add(new SimpleMappingExceptionResolver());
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
      configurer.setPathMatcher(new TestPathMatcher());
      configurer.setUrlPathHelper(new TestPathHelper());
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(new LocaleChangeInterceptor());
    }

    @SuppressWarnings("serial")
    @Override
    public MessageCodesResolver getMessageCodesResolver() {
      return new DefaultMessageCodesResolver() {
        @Override
        public String[] resolveMessageCodes(String errorCode, String objectName) {
          return new String[] { "custom." + errorCode };
        }
      };
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
      registry.addViewController("/path").setViewName("view");
      registry.addRedirectViewController("/old", "/new").setStatusCode(HttpStatus.PERMANENT_REDIRECT);
      registry.addStatusController("/bad", HttpStatus.NOT_FOUND);
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
      registry.enableContentNegotiation(new MappingJackson2JsonView());
      registry.jsp("/", ".jsp");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
      registry.addResourceHandler("/resources/**").addResourceLocations("src/test/java");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
      configurer.enable("default");
    }
  }

  private class TestPathHelper extends UrlPathHelper {}

  private class TestPathMatcher extends AntPathMatcher {}
}
TOP

Related Classes of org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupportExtensionTests$TestPathHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.