Add naming strategy for @MVC request mappings.

This change adds a strategy for assigning a default name to an
@RequestMapping controller method. The @RequestMapping annotation
itself now has a name attribute allowing the explicit assignment
of a mapping name.

This is mainly intended for use in EL expressions in views. The
RequestContext class now provides a getMvcUrl method that internally
delegates to MvcUriComponents to look up the handler method.

See the Javadoc of MvcUriComponents.fromMappingName.

Issue: SPR-5779
This commit is contained in:
Rossen Stoyanchev
2014-05-06 15:18:31 -04:00
parent 381ccde48d
commit 9d479feadd
14 changed files with 500 additions and 52 deletions

View File

@@ -266,6 +266,18 @@ import java.util.concurrent.Callable;
@Mapping
public @interface RequestMapping {
/**
* Assign a name to this mapping.
* <p><b>Supported at the method and also at type level!</b>
* When used on both levels, a combined name is derived by
* concatenation with "#" as separator.
*
* @see org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder
* @see org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy
*/
String name() default "";
/**
* The primary mapping expressed by this annotation.
* <p>In a Servlet environment: the path mapping URIs (e.g. "/myPath.do").

View File

@@ -256,34 +256,45 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod
}
@Override
public void contributeMethodArgument(MethodParameter parameter, Object value,
public void contributeMethodArgument(MethodParameter param, Object value,
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) {
Class<?> paramType = parameter.getParameterType();
Class<?> paramType = param.getParameterType();
if (Map.class.isAssignableFrom(paramType) || MultipartFile.class.equals(paramType) ||
"javax.servlet.http.Part".equals(paramType.getName())) {
return;
}
RequestParam annot = parameter.getParameterAnnotation(RequestParam.class);
String name = StringUtils.isEmpty(annot.value()) ? parameter.getParameterName() : annot.value();
RequestParam annot = param.getParameterAnnotation(RequestParam.class);
String name = (annot == null || StringUtils.isEmpty(annot.value()) ? param.getParameterName() : annot.value());
if (value == null) {
builder.queryParam(name);
}
else if (value instanceof Collection) {
for (Object element : (Collection<?>) value) {
element = formatUriValue(conversionService, TypeDescriptor.nested(parameter, 1), element);
element = formatUriValue(conversionService, TypeDescriptor.nested(param, 1), element);
builder.queryParam(name, element);
}
}
else {
builder.queryParam(name, formatUriValue(conversionService, new TypeDescriptor(parameter), value));
builder.queryParam(name, formatUriValue(conversionService, new TypeDescriptor(param), value));
}
}
protected String formatUriValue(ConversionService cs, TypeDescriptor sourceType, Object value) {
return (cs != null ? (String) cs.convert(value, sourceType, STRING_TYPE_DESCRIPTOR) : null);
if (value == null) {
return null;
}
else if (value instanceof String) {
return (String) value;
}
else if (cs != null) {
return (String) cs.convert(value, sourceType, STRING_TYPE_DESCRIPTOR);
}
else {
return value.toString();
}
}

View File

@@ -38,7 +38,7 @@ import org.springframework.web.util.UriComponentsBuilder;
*/
public class CompositeUriComponentsContributor implements UriComponentsContributor {
private final List<UriComponentsContributor> contributors = new LinkedList<UriComponentsContributor>();
private final List<Object> contributors = new LinkedList<Object>();
private final ConversionService conversionService;
@@ -81,18 +81,13 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
* will be used by default.
* @param contributors a collection of {@link UriComponentsContributor}
* or {@link HandlerMethodArgumentResolver}s.
* @param conversionService a ConversionService to use when method argument values
* @param cs a ConversionService to use when method argument values
* need to be formatted as Strings before being added to the URI
*/
public CompositeUriComponentsContributor(Collection<?> contributors, ConversionService conversionService) {
public CompositeUriComponentsContributor(Collection<?> contributors, ConversionService cs) {
Assert.notNull(contributors, "'uriComponentsContributors' must not be null");
for (Object contributor : contributors) {
if (contributor instanceof UriComponentsContributor) {
this.contributors.add((UriComponentsContributor) contributor);
}
}
this.conversionService =
(conversionService != null ? conversionService : new DefaultFormattingConversionService());
this.contributors.addAll(contributors);
this.conversionService = (cs != null ? cs : new DefaultFormattingConversionService());
}
@@ -102,9 +97,17 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
@Override
public boolean supportsParameter(MethodParameter parameter) {
for (UriComponentsContributor contributor : this.contributors) {
if (contributor.supportsParameter(parameter)) {
return true;
for (Object c : this.contributors) {
if (c instanceof UriComponentsContributor) {
UriComponentsContributor contributor = (UriComponentsContributor) c;
if (contributor.supportsParameter(parameter)) {
return true;
}
}
else if (c instanceof HandlerMethodArgumentResolver) {
if (((HandlerMethodArgumentResolver) c).supportsParameter(parameter)) {
return false;
}
}
}
return false;
@@ -114,10 +117,18 @@ public class CompositeUriComponentsContributor implements UriComponentsContribut
public void contributeMethodArgument(MethodParameter parameter, Object value,
UriComponentsBuilder builder, Map<String, Object> uriVariables, ConversionService conversionService) {
for (UriComponentsContributor contributor : this.contributors) {
if (contributor.supportsParameter(parameter)) {
contributor.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService);
break;
for (Object c : this.contributors) {
if (c instanceof UriComponentsContributor) {
UriComponentsContributor contributor = (UriComponentsContributor) c;
if (contributor.supportsParameter(parameter)) {
contributor.contributeMethodArgument(parameter, value, builder, uriVariables, conversionService);
break;
}
}
else if (c instanceof HandlerMethodArgumentResolver) {
if (((HandlerMethodArgumentResolver) c).supportsParameter(parameter)) {
break;
}
}
}
}