2121import java .util .HashMap ;
2222import java .util .List ;
2323import java .util .Map ;
24+
2425import javax .servlet .http .HttpServletRequest ;
2526
2627import org .aopalliance .intercept .MethodInterceptor ;
@@ -122,8 +123,28 @@ protected MvcUriComponentsBuilder(MvcUriComponentsBuilder other) {
122123 * @return a UriComponentsBuilder instance (never {@code null})
123124 */
124125 public static UriComponentsBuilder fromController (Class <?> controllerType ) {
126+ return fromController (null , controllerType );
127+ }
128+
129+ /**
130+ * An alternative to {@link #fromController(Class)} that accepts a
131+ * {@code UriComponentsBuilder} representing the base URL. This is useful
132+ * when using MvcUriComponentsBuilder outside the context of processing a
133+ * request or to apply a custom baseUrl not matching the current request.
134+ * @param builder the builder for the base URL; the builder will be cloned
135+ * and therefore not modified and may be re-used for further calls.
136+ * @param controllerType the controller to build a URI for
137+ * @return a UriComponentsBuilder instance (never {@code null})
138+ */
139+ public static UriComponentsBuilder fromController (UriComponentsBuilder builder , Class <?> controllerType ) {
140+ if (builder != null ) {
141+ builder = (UriComponentsBuilder ) builder .clone ();
142+ }
143+ else {
144+ builder = ServletUriComponentsBuilder .fromCurrentServletMapping ();
145+ }
125146 String mapping = getTypeRequestMapping (controllerType );
126- return ServletUriComponentsBuilder . fromCurrentServletMapping () .path (mapping );
147+ return builder .path (mapping );
127148 }
128149
129150 private static String getTypeRequestMapping (Class <?> controllerType ) {
@@ -144,29 +165,49 @@ private static String getTypeRequestMapping(Class<?> controllerType) {
144165 * to {@link #fromMethod(java.lang.reflect.Method, Object...)}.
145166 * @param controllerType the controller
146167 * @param methodName the method name
147- * @param argumentValues the argument values
168+ * @param args the argument values
148169 * @return a UriComponentsBuilder instance, never {@code null}
149170 * @throws IllegalArgumentException if there is no matching or
150171 * if there is more than one matching method
151172 */
152- public static UriComponentsBuilder fromMethodName (Class <?> controllerType , String methodName , Object ... argumentValues ) {
153- Method method = getMethod (controllerType , methodName , argumentValues );
154- return fromMethod (method , argumentValues );
173+ public static UriComponentsBuilder fromMethodName (Class <?> controllerType , String methodName , Object ... args ) {
174+ return fromMethodName (null , controllerType , methodName , args );
155175 }
156176
157- private static Method getMethod (Class <?> controllerType , String methodName , Object ... argumentValues ) {
177+ /**
178+ * An alternative to {@link #fromMethodName(Class, String, Object...)} that
179+ * accepts a {@code UriComponentsBuilder} representing the base URL. This is
180+ * useful when using MvcUriComponentsBuilder outside the context of processing
181+ * a request or to apply a custom baseUrl not matching the current request.
182+ * @param builder the builder for the base URL; the builder will be cloned
183+ * and therefore not modified and may be re-used for further calls.
184+ * @param controllerType the controller
185+ * @param methodName the method name
186+ * @param args the argument values
187+ * @return a UriComponentsBuilder instance, never {@code null}
188+ * @throws IllegalArgumentException if there is no matching or
189+ * if there is more than one matching method
190+ */
191+ public static UriComponentsBuilder fromMethodName (UriComponentsBuilder builder ,
192+ Class <?> controllerType , String methodName , Object ... args ) {
193+
194+ Method method = getMethod (controllerType , methodName , args );
195+ return fromMethod (builder , method , args );
196+ }
197+
198+ private static Method getMethod (Class <?> controllerType , String methodName , Object ... args ) {
158199 Method match = null ;
159200 for (Method method : controllerType .getDeclaredMethods ()) {
160- if (method .getName ().equals (methodName ) && method .getParameterTypes ().length == argumentValues .length ) {
201+ if (method .getName ().equals (methodName ) && method .getParameterTypes ().length == args .length ) {
161202 if (match != null ) {
162203 throw new IllegalArgumentException ("Found two methods named '" + methodName + "' having " +
163- Arrays .asList (argumentValues ) + " arguments, controller " + controllerType .getName ());
204+ Arrays .asList (args ) + " arguments, controller " + controllerType .getName ());
164205 }
165206 match = method ;
166207 }
167208 }
168209 if (match == null ) {
169- throw new IllegalArgumentException ("No method '" + methodName + "' with " + argumentValues .length +
210+ throw new IllegalArgumentException ("No method '" + methodName + "' with " + args .length +
170211 " parameters found in " + controllerType .getName ());
171212 }
172213 return match ;
@@ -208,9 +249,24 @@ private static Method getMethod(Class<?> controllerType, String methodName, Obje
208249 * @return a UriComponents instance
209250 */
210251 public static UriComponentsBuilder fromMethodCall (Object invocationInfo ) {
252+ return fromMethodCall (null , invocationInfo );
253+ }
254+
255+ /**
256+ * An alternative to {@link #fromMethodCall(Object)} that accepts a
257+ * {@code UriComponentsBuilder} representing the base URL. This is useful
258+ * when using MvcUriComponentsBuilder outside the context of processing a
259+ * request or to apply a custom baseUrl not matching the current request.
260+ * @param builder the builder for the base URL; the builder will be cloned
261+ * and therefore not modified and may be re-used for further calls.
262+ * @param invocationInfo either the value returned from a "mock" controller
263+ * invocation or the "mock" controller itself after an invocation
264+ * @return a UriComponents instance
265+ */
266+ public static UriComponentsBuilder fromMethodCall (UriComponentsBuilder builder , Object invocationInfo ) {
211267 Assert .isInstanceOf (MethodInvocationInfo .class , invocationInfo );
212268 MethodInvocationInfo info = (MethodInvocationInfo ) invocationInfo ;
213- return fromMethod (info .getControllerMethod (), info .getArgumentValues ());
269+ return fromMethod (builder , info .getControllerMethod (), info .getArgumentValues ());
214270 }
215271
216272 /**
@@ -277,20 +333,42 @@ public static MethodArgumentBuilder fromMappingName(String mappingName) {
277333 * and an array of method argument values. The array of values must match the
278334 * signature of the controller method. Values for {@code @RequestParam} and
279335 * {@code @PathVariable} are used for building the URI (via implementations of
280- * {@link org.springframework.web.method.support.UriComponentsContributor})
281- * while remaining argument values are ignored and can be {@code null}.
336+ * {@link org.springframework.web.method.support.UriComponentsContributor
337+ * UriComponentsContributor}) while remaining argument values are ignored and
338+ * can be {@code null}.
339+ * @param method the controller method
340+ * @param args argument values for the controller method
341+ * @return a UriComponentsBuilder instance, never {@code null}
342+ */
343+ public static UriComponentsBuilder fromMethod (Method method , Object ... args ) {
344+ return fromMethod (null , method , args );
345+ }
346+
347+ /**
348+ * An alternative to {@link #fromMethod(java.lang.reflect.Method, Object...)}
349+ * that accepts a {@code UriComponentsBuilder} representing the base URL.
350+ * This is useful when using MvcUriComponentsBuilder outside the context of
351+ * processing a request or to apply a custom baseUrl not matching the
352+ * current request.
353+ * @param builder the builder for the base URL; the builder will be cloned
354+ * and therefore not modified and may be re-used for further calls.
282355 * @param method the controller method
283- * @param argumentValues argument values for the controller method
356+ * @param args argument values for the controller method
284357 * @return a UriComponentsBuilder instance, never {@code null}
285358 */
286- public static UriComponentsBuilder fromMethod (Method method , Object ... argumentValues ) {
359+ public static UriComponentsBuilder fromMethod (UriComponentsBuilder builder , Method method , Object ... args ) {
360+ if (builder != null ) {
361+ builder = (UriComponentsBuilder ) builder .clone ();
362+ }
363+ else {
364+ builder = ServletUriComponentsBuilder .fromCurrentServletMapping ();
365+ }
287366 String typePath = getTypeRequestMapping (method .getDeclaringClass ());
288367 String methodPath = getMethodRequestMapping (method );
289368 String path = pathMatcher .combine (typePath , methodPath );
290-
291- UriComponentsBuilder builder = ServletUriComponentsBuilder .fromCurrentServletMapping ().path (path );
292- UriComponents uriComponents = applyContributors (builder , method , argumentValues );
293- return ServletUriComponentsBuilder .newInstance ().uriComponents (uriComponents );
369+ builder .path (path );
370+ UriComponents uriComponents = applyContributors (builder , method , args );
371+ return UriComponentsBuilder .newInstance ().uriComponents (uriComponents );
294372 }
295373
296374 private static String getMethodRequestMapping (Method method ) {
@@ -453,7 +531,7 @@ private static <T> T initProxy(Class<?> type, ControllerMethodInvocationIntercep
453531 }
454532
455533 @ Override
456- protected Object clone () {
534+ public Object clone () {
457535 return new MvcUriComponentsBuilder (this );
458536 }
459537
0 commit comments