1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.web.servlet.mvc.method.annotation;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.springframework.core.MethodParameter;
24 import org.springframework.util.CollectionUtils;
25 import org.springframework.util.MultiValueMap;
26 import org.springframework.util.StringUtils;
27 import org.springframework.web.bind.ServletRequestBindingException;
28 import org.springframework.web.bind.annotation.MatrixVariable;
29 import org.springframework.web.bind.annotation.ValueConstants;
30 import org.springframework.web.context.request.NativeWebRequest;
31 import org.springframework.web.context.request.RequestAttributes;
32 import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver;
33 import org.springframework.web.servlet.HandlerMapping;
34
35
36
37
38
39
40
41
42
43
44 public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
45
46 public MatrixVariableMethodArgumentResolver() {
47 super(null);
48 }
49
50 @Override
51 public boolean supportsParameter(MethodParameter parameter) {
52 if (!parameter.hasParameterAnnotation(MatrixVariable.class)) {
53 return false;
54 }
55 if (Map.class.isAssignableFrom(parameter.getParameterType())) {
56 String paramName = parameter.getParameterAnnotation(MatrixVariable.class).value();
57 return StringUtils.hasText(paramName);
58 }
59 return true;
60 }
61
62 @Override
63 protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
64 MatrixVariable annotation = parameter.getParameterAnnotation(MatrixVariable.class);
65 return new PathParamNamedValueInfo(annotation);
66 }
67
68 @Override
69 protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
70
71 @SuppressWarnings("unchecked")
72 Map<String, MultiValueMap<String, String>> pathParameters =
73 (Map<String, MultiValueMap<String, String>>) request.getAttribute(
74 HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
75
76 if (CollectionUtils.isEmpty(pathParameters)) {
77 return null;
78 }
79
80 String pathVar = parameter.getParameterAnnotation(MatrixVariable.class).pathVar();
81 List<String> paramValues = null;
82
83 if (!pathVar.equals(ValueConstants.DEFAULT_NONE)) {
84 if (pathParameters.containsKey(pathVar)) {
85 paramValues = pathParameters.get(pathVar).get(name);
86 }
87 }
88 else {
89 boolean found = false;
90 paramValues = new ArrayList<String>();
91 for (MultiValueMap<String, String> params : pathParameters.values()) {
92 if (params.containsKey(name)) {
93 if (found) {
94 String paramType = parameter.getParameterType().getName();
95 throw new ServletRequestBindingException(
96 "Found more than one match for URI path parameter '" + name +
97 "' for parameter type [" + paramType + "]. Use pathVar attribute to disambiguate.");
98 }
99 paramValues.addAll(params.get(name));
100 found = true;
101 }
102 }
103 }
104
105 if (CollectionUtils.isEmpty(paramValues)) {
106 return null;
107 }
108 else if (paramValues.size() == 1) {
109 return paramValues.get(0);
110 }
111 else {
112 return paramValues;
113 }
114 }
115
116 @Override
117 protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {
118 throw new ServletRequestBindingException("Missing matrix variable '" + name +
119 "' for method parameter of type " + parameter.getParameterType().getSimpleName());
120 }
121
122
123 private static class PathParamNamedValueInfo extends NamedValueInfo {
124
125 private PathParamNamedValueInfo(MatrixVariable annotation) {
126 super(annotation.value(), annotation.required(), annotation.defaultValue());
127 }
128 }
129 }