org.springframework.beans.propertyeditors.StringTrimmerEditor#org.springframework.web.bind.support.WebDataBinderFactory源码实例Demo

下面列出了org.springframework.beans.propertyeditors.StringTrimmerEditor#org.springframework.web.bind.support.WebDataBinderFactory 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

/**
 * Instantiate the model attribute from a URI template variable or from a
 * request parameter if the name matches to the model attribute name and
 * if there is an appropriate type conversion strategy. If none of these
 * are true delegate back to the base class.
 * @see #createAttributeFromRequestValue
 */
@Override
protected final Object createAttribute(String attributeName, MethodParameter parameter,
		WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {

	String value = getRequestValueForAttribute(attributeName, request);
	if (value != null) {
		Object attribute = createAttributeFromRequestValue(
				value, attributeName, parameter, binderFactory, request);
		if (attribute != null) {
			return attribute;
		}
	}

	return super.createAttribute(attributeName, parameter, binderFactory, request);
}
 
/**
 * Create a model attribute from a String request value (e.g. URI template
 * variable, request parameter) using type conversion.
 * <p>The default implementation converts only if there a registered
 * {@link Converter} that can perform the conversion.
 * @param sourceValue the source value to create the model attribute from
 * @param attributeName the name of the attribute (never {@code null})
 * @param parameter the method parameter
 * @param binderFactory for creating WebDataBinder instance
 * @param request the current request
 * @return the created model attribute, or {@code null} if no suitable
 * conversion found
 */
@Nullable
protected Object createAttributeFromRequestValue(String sourceValue, String attributeName,
		MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request)
		throws Exception {

	DataBinder binder = binderFactory.createBinder(request, null, attributeName);
	ConversionService conversionService = binder.getConversionService();
	if (conversionService != null) {
		TypeDescriptor source = TypeDescriptor.valueOf(String.class);
		TypeDescriptor target = new TypeDescriptor(parameter);
		if (conversionService.canConvert(source, target)) {
			return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
		}
	}
	return null;
}
 
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
		throws IOException, HttpMediaTypeNotSupportedException {

	ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
	Type paramType = getHttpEntityType(parameter);
	if (paramType == null) {
		throw new IllegalArgumentException("HttpEntity parameter '" + parameter.getParameterName() +
				"' in method " + parameter.getMethod() + " is not parameterized");
	}

	Object body = readWithMessageConverters(webRequest, parameter, paramType);
	if (RequestEntity.class == parameter.getParameterType()) {
		return new RequestEntity<>(body, inputMessage.getHeaders(),
				inputMessage.getMethod(), inputMessage.getURI());
	}
	else {
		return new HttpEntity<>(body, inputMessage.getHeaders());
	}
}
 
/**
 * Delegate to the {@link WebArgumentResolver} instance.
 * @throws IllegalStateException if the resolved value is not assignable
 * to the method parameter.
 */
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	Class<?> paramType = parameter.getParameterType();
	Object result = this.adaptee.resolveArgument(parameter, webRequest);
	if (result == WebArgumentResolver.UNRESOLVED || !ClassUtils.isAssignableValue(paramType, result)) {
		throw new IllegalStateException(
				"Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() +
				"resolved to incompatible value of type [" + (result != null ? result.getClass() : null) +
				"]. Consider declaring the argument type in a less specific fashion.");
	}
	return result;
}
 
/**
 * Return a Map with all URI template variables or an empty map.
 */
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	@SuppressWarnings("unchecked")
	Map<String, String> uriTemplateVars =
			(Map<String, String>) webRequest.getAttribute(
					HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);

	if (!CollectionUtils.isEmpty(uriTemplateVars)) {
		return new LinkedHashMap<>(uriTemplateVars);
	}
	else {
		return Collections.emptyMap();
	}
}
 
/**
 * Throws MethodArgumentNotValidException if validation fails.
 * @throws HttpMessageNotReadableException if {@link RequestBody#required()}
 * is {@code true} and there is no body content or if there is no suitable
 * converter to read the content with.
 */
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	parameter = parameter.nestedIfOptional();
	Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
	String name = Conventions.getVariableNameForParameter(parameter);

	if (binderFactory != null) {
		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
		if (arg != null) {
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
			}
		}
		if (mavContainer != null) {
			mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
		}
	}

	return adaptArgumentIfNecessary(arg, parameter);
}
 
@Test
public void resolveOptional() throws Exception {
	WebDataBinder dataBinder = new WebRequestDataBinder(null);
	dataBinder.setConversionService(new DefaultConversionService());
	WebDataBinderFactory factory = mock(WebDataBinderFactory.class);
	given(factory.createBinder(this.webRequest, null, "foo")).willReturn(dataBinder);

	MethodParameter param = initMethodParameter(3);
	Object actual = testResolveArgument(param, factory);
	assertNotNull(actual);
	assertEquals(Optional.class, actual.getClass());
	assertFalse(((Optional<?>) actual).isPresent());

	Foo foo = new Foo();
	this.webRequest.setAttribute("foo", foo, getScope());

	actual = testResolveArgument(param, factory);
	assertNotNull(actual);
	assertEquals(Optional.class, actual.getClass());
	assertTrue(((Optional<?>) actual).isPresent());
	assertSame(foo, ((Optional<?>) actual).get());
}
 
/**
 * Set {@link ModelAndViewContainer#setRequestHandled(boolean)} to
 * {@code false} to indicate that the method signature provides access
 * to the response. If subsequently the underlying method returns
 * {@code null}, the request is considered directly handled.
 */
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	if (mavContainer != null) {
		mavContainer.setRequestHandled(true);
	}

	Class<?> paramType = parameter.getParameterType();

	// ServletResponse, HttpServletResponse
	if (ServletResponse.class.isAssignableFrom(paramType)) {
		return resolveNativeResponse(webRequest, paramType);
	}

	// ServletResponse required for all further argument types
	return resolveArgument(paramType, resolveNativeResponse(webRequest, ServletResponse.class));
}
 
@Test
public void resolveArgumentWrappedAsOptional() throws Exception {
	Map<String, String> uriTemplateVars = new HashMap<>();
	uriTemplateVars.put("name", "value");
	request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars);

	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	@SuppressWarnings("unchecked")
	Optional<String> result = (Optional<String>)
			resolver.resolveArgument(paramOptional, mavContainer, webRequest, binderFactory);
	assertEquals("PathVariable not resolved correctly", "value", result.get());

	@SuppressWarnings("unchecked")
	Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES);
	assertNotNull(pathVars);
	assertEquals(1, pathVars.size());
	assertEquals(Optional.of("value"), pathVars.get("name"));
}
 
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter,
		@Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
		@Nullable WebDataBinderFactory binderFactory) throws Exception {

	Assert.state(mavContainer != null,
			"Errors/BindingResult argument only supported on regular handler methods");

	ModelMap model = mavContainer.getModel();
	String lastKey = CollectionUtils.lastElement(model.keySet());
	if (lastKey != null && lastKey.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
		return model.get(lastKey);
	}

	throw new IllegalStateException(
			"An Errors/BindingResult argument is expected to be declared immediately after " +
			"the model attribute, the @RequestBody or the @RequestPart arguments " +
			"to which they apply: " + parameter.getMethod());
}
 
@Test
@SuppressWarnings("rawtypes")
public void resolveOptionalParamList() throws Exception {
	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, List.class);
	Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.empty(), result);

	request.addParameter("name", "123", "456");
	result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.class, result.getClass());
	assertEquals(Arrays.asList("123", "456"), ((Optional) result).get());
}
 
@Test
public void resolveOptional() throws Exception {
	WebDataBinder dataBinder = new WebRequestDataBinder(null);
	dataBinder.setConversionService(new DefaultConversionService());
	WebDataBinderFactory factory = mock(WebDataBinderFactory.class);
	given(factory.createBinder(this.webRequest, null, "foo")).willReturn(dataBinder);

	MethodParameter param = initMethodParameter(3);
	Object actual = testResolveArgument(param, factory);
	assertNotNull(actual);
	assertEquals(Optional.class, actual.getClass());
	assertFalse(((Optional<?>) actual).isPresent());

	Foo foo = new Foo();
	this.webRequest.setAttribute("foo", foo, getScope());

	actual = testResolveArgument(param, factory);
	assertNotNull(actual);
	assertEquals(Optional.class, actual.getClass());
	assertTrue(((Optional<?>) actual).isPresent());
	assertSame(foo, ((Optional<?>) actual).get());
}
 
@Test  // SPR-9378
public void resolveArgumentOrdering() throws Exception {
	String name = "testBean";
	Object testBean = new TestBean(name);
	this.container.addAttribute(name, testBean);
	this.container.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, testBean);

	Object anotherTestBean = new TestBean();
	this.container.addAttribute("anotherTestBean", anotherTestBean);

	StubRequestDataBinder dataBinder = new StubRequestDataBinder(testBean, name);
	WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
	given(binderFactory.createBinder(this.request, testBean, name)).willReturn(dataBinder);

	this.processor.resolveArgument(this.paramModelAttr, this.container, this.request, binderFactory);

	Object[] values = this.container.getModel().values().toArray();
	assertSame("Resolved attribute should be updated to be last", testBean, values[1]);
	assertSame("BindingResult of resolved attr should be last", dataBinder.getBindingResult(), values[2]);
}
 
@Test
@SuppressWarnings("rawtypes")
public void resolveOptionalParamValue() throws Exception {
	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, Integer.class);
	Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.empty(), result);

	request.addParameter("name", "123");
	result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.class, result.getClass());
	assertEquals(123, ((Optional) result).get());
}
 
@Test
@SuppressWarnings("rawtypes")
public void resolveOptionalParamArray() throws Exception {
	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, Integer[].class);
	Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.empty(), result);

	request.addParameter("name", "123", "456");
	result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.class, result.getClass());
	assertArrayEquals(new Integer[] {123, 456}, (Integer[]) ((Optional) result).get());
}
 
/**
 * Return a Map with all URI template variables or an empty map.
 */
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	@SuppressWarnings("unchecked")
	Map<String, String> uriTemplateVars =
			(Map<String, String>) webRequest.getAttribute(
					HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);

	if (!CollectionUtils.isEmpty(uriTemplateVars)) {
		return new LinkedHashMap<>(uriTemplateVars);
	}
	else {
		return Collections.emptyMap();
	}
}
 
@Test
public void resolveOptionalMultipartFile() throws Exception {
	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
	MultipartFile expected = new MockMultipartFile("mfile", "Hello World".getBytes());
	request.addFile(expected);
	webRequest = new ServletWebRequest(request);

	MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, MultipartFile.class);
	Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);

	assertTrue(result instanceof Optional);
	assertEquals("Invalid result", expected, ((Optional<?>) result).get());
}
 
@Test
@SuppressWarnings("rawtypes")
public void resolveOptionalParamArray() throws Exception {
	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	MethodParameter param = this.testMethod.annotPresent(RequestParam.class).arg(Optional.class, Integer[].class);
	Object result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.empty(), result);

	request.addParameter("name", "123", "456");
	result = resolver.resolveArgument(param, null, webRequest, binderFactory);
	assertEquals(Optional.class, result.getClass());
	assertArrayEquals(new Integer[] {123, 456}, (Integer[]) ((Optional) result).get());
}
 
源代码19 项目: spring-analysis-note   文件: ModelFactoryTests.java
@Test
public void updateModelSessionAttributesSaved() throws Exception {
	String attributeName = "sessionAttr";
	String attribute = "value";
	ModelAndViewContainer container = new ModelAndViewContainer();
	container.addAttribute(attributeName, attribute);

	WebDataBinder dataBinder = new WebDataBinder(attribute, attributeName);
	WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
	given(binderFactory.createBinder(this.webRequest, attribute, attributeName)).willReturn(dataBinder);

	ModelFactory modelFactory = new ModelFactory(null, binderFactory, this.attributeHandler);
	modelFactory.updateModel(this.webRequest, container);

	assertEquals(attribute, container.getModel().get(attributeName));
	assertEquals(attribute, this.attributeStore.retrieveAttribute(this.webRequest, attributeName));
}
 
源代码20 项目: spring-analysis-note   文件: ModelFactoryTests.java
@Test  // SPR-12542
public void updateModelWhenRedirecting() throws Exception {
	String attributeName = "sessionAttr";
	String attribute = "value";
	ModelAndViewContainer container = new ModelAndViewContainer();
	container.addAttribute(attributeName, attribute);

	String queryParam = "123";
	String queryParamName = "q";
	container.setRedirectModel(new ModelMap(queryParamName, queryParam));
	container.setRedirectModelScenario(true);

	WebDataBinder dataBinder = new WebDataBinder(attribute, attributeName);
	WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
	given(binderFactory.createBinder(this.webRequest, attribute, attributeName)).willReturn(dataBinder);

	ModelFactory modelFactory = new ModelFactory(null, binderFactory, this.attributeHandler);
	modelFactory.updateModel(this.webRequest, container);

	assertEquals(queryParam, container.getModel().get(queryParamName));
	assertEquals(1, container.getModel().size());
	assertEquals(attribute, this.attributeStore.retrieveAttribute(this.webRequest, attributeName));
}
 
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory binderFactory) throws Exception {
    RequestJsonToPo parameterAnnotation = parameter.getParameterAnnotation(RequestJsonToPo.class);
    Objects.requireNonNull(parameterAnnotation);
    String value = parameterAnnotation.value();
    Class<?> clazz = parameter.getNestedParameterType();
    String jsonParameter = nativeWebRequest.getParameter(value);
    if (jsonParameter == null) {
        if (clazz.isAssignableFrom(List.class)) {
            return Lists.newArrayList();
        }
        return clazz.newInstance();
    }
    jsonParameter = URLDecoder.decode(jsonParameter, StandardCharsets.UTF_8.name());

    if (clazz.isAssignableFrom(List.class) || clazz.isAssignableFrom(ArrayList.class)) {
        String typeName = ((sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl) parameter.getGenericParameterType()).getActualTypeArguments()[0].getTypeName();
        Class<?> aClass = Class.forName(typeName);
        return JsonUtil.toList(jsonParameter, aClass);
    } else {
        return JsonUtil.toObject(jsonParameter, clazz);
    }
}
 
/**
 * Instantiate the model attribute from a URI template variable or from a
 * request parameter if the name matches to the model attribute name and
 * if there is an appropriate type conversion strategy. If none of these
 * are true delegate back to the base class.
 * @see #createAttributeFromRequestValue
 */
@Override
protected final Object createAttribute(String attributeName, MethodParameter parameter,
		WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {

	String value = getRequestValueForAttribute(attributeName, request);
	if (value != null) {
		Object attribute = createAttributeFromRequestValue(
				value, attributeName, parameter, binderFactory, request);
		if (attribute != null) {
			return attribute;
		}
	}

	return super.createAttribute(attributeName, parameter, binderFactory, request);
}
 
/**
 * Create a model attribute from a String request value (e.g. URI template
 * variable, request parameter) using type conversion.
 * <p>The default implementation converts only if there a registered
 * {@link Converter} that can perform the conversion.
 * @param sourceValue the source value to create the model attribute from
 * @param attributeName the name of the attribute (never {@code null})
 * @param parameter the method parameter
 * @param binderFactory for creating WebDataBinder instance
 * @param request the current request
 * @return the created model attribute, or {@code null} if no suitable
 * conversion found
 */
@Nullable
protected Object createAttributeFromRequestValue(String sourceValue, String attributeName,
		MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request)
		throws Exception {

	DataBinder binder = binderFactory.createBinder(request, null, attributeName);
	ConversionService conversionService = binder.getConversionService();
	if (conversionService != null) {
		TypeDescriptor source = TypeDescriptor.valueOf(String.class);
		TypeDescriptor target = new TypeDescriptor(parameter);
		if (conversionService.canConvert(source, target)) {
			return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
		}
	}
	return null;
}
 
@Test  // SPR-9378
public void resolveArgumentOrdering() throws Exception {
	String name = "testBean";
	Object testBean = new TestBean(name);
	this.container.addAttribute(name, testBean);
	this.container.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, testBean);

	Object anotherTestBean = new TestBean();
	this.container.addAttribute("anotherTestBean", anotherTestBean);

	StubRequestDataBinder dataBinder = new StubRequestDataBinder(testBean, name);
	WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
	given(binderFactory.createBinder(this.request, testBean, name)).willReturn(dataBinder);

	this.processor.resolveArgument(this.paramModelAttr, this.container, this.request, binderFactory);

	Object[] values = this.container.getModel().values().toArray();
	assertSame("Resolved attribute should be updated to be last", testBean, values[1]);
	assertSame("BindingResult of resolved attr should be last", dataBinder.getBindingResult(), values[2]);
}
 
/**
 * Extension point to create the model attribute if not found in the model,
 * with subsequent parameter binding through bean properties (unless suppressed).
 * <p>The default implementation typically uses the unique public no-arg constructor
 * if available but also handles a "primary constructor" approach for data classes:
 * It understands the JavaBeans {@link ConstructorProperties} annotation as well as
 * runtime-retained parameter names in the bytecode, associating request parameters
 * with constructor arguments by name. If no such constructor is found, the default
 * constructor will be used (even if not public), assuming subsequent bean property
 * bindings through setter methods.
 * @param attributeName the name of the attribute (never {@code null})
 * @param parameter the method parameter declaration
 * @param binderFactory for creating WebDataBinder instance
 * @param webRequest the current request
 * @return the created model attribute (never {@code null})
 * @throws BindException in case of constructor argument binding failure
 * @throws Exception in case of constructor invocation failure
 * @see #constructAttribute(Constructor, String, MethodParameter, WebDataBinderFactory, NativeWebRequest)
 * @see BeanUtils#findPrimaryConstructor(Class)
 */
protected Object createAttribute(String attributeName, MethodParameter parameter,
		WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {

	MethodParameter nestedParameter = parameter.nestedIfOptional();
	Class<?> clazz = nestedParameter.getNestedParameterType();

	Constructor<?> ctor = BeanUtils.findPrimaryConstructor(clazz);
	if (ctor == null) {
		Constructor<?>[] ctors = clazz.getConstructors();
		if (ctors.length == 1) {
			ctor = ctors[0];
		}
		else {
			try {
				ctor = clazz.getDeclaredConstructor();
			}
			catch (NoSuchMethodException ex) {
				throw new IllegalStateException("No primary or default constructor found for " + clazz, ex);
			}
		}
	}

	Object attribute = constructAttribute(ctor, attributeName, parameter, binderFactory, webRequest);
	if (parameter != nestedParameter) {
		attribute = Optional.of(attribute);
	}
	return attribute;
}
 
@Test
public void wrapEmptyWithOptional() throws Exception {
	ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
	initializer.setConversionService(new DefaultConversionService());
	WebDataBinderFactory binderFactory = new DefaultDataBinderFactory(initializer);

	assertEquals(Optional.empty(), resolver.resolveArgument(paramOptional, mavContainer, webRequest, binderFactory));
}
 
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest request, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	@SuppressWarnings("unchecked")
	Map<String, MultiValueMap<String, String>> matrixVariables =
			(Map<String, MultiValueMap<String, String>>) request.getAttribute(
					HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);

	if (CollectionUtils.isEmpty(matrixVariables)) {
		return Collections.emptyMap();
	}

	MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
	MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
	Assert.state(ann != null, "No MatrixVariable annotation");
	String pathVariable = ann.pathVar();

	if (!pathVariable.equals(ValueConstants.DEFAULT_NONE)) {
		MultiValueMap<String, String> mapForPathVariable = matrixVariables.get(pathVariable);
		if (mapForPathVariable == null) {
			return Collections.emptyMap();
		}
		map.putAll(mapForPathVariable);
	}
	else {
		for (MultiValueMap<String, String> vars : matrixVariables.values()) {
			vars.forEach((name, values) -> {
				for (String value : values) {
					map.add(name, value);
				}
			});
		}
	}

	return (isSingleValueMap(parameter) ? map.toSingleValueMap() : map);
}
 
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

	HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
	Assert.state(request != null, "No HttpServletRequest");
	return ServletUriComponentsBuilder.fromServletMapping(request);
}
 
private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
	InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
	if (this.argumentResolvers != null) {
		attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
	}
	attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
	attrMethod.setDataBinderFactory(factory);
	return attrMethod;
}
 
/**
 * Construct a new attribute instance with the given constructor.
 * @since 5.0
 * @deprecated as of 5.1, in favor of
 * {@link #constructAttribute(Constructor, String, MethodParameter, WebDataBinderFactory, NativeWebRequest)}
 */
@Deprecated
@Nullable
protected Object constructAttribute(Constructor<?> ctor, String attributeName,
		WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {

	return null;
}