#26, #39 - Added support for request parameters to ControllerLinkBuilder.

We now transparently handle "?foo=bar" expressions passed into ….slash(…). Added method to return UriComponentsBuilder to allow more fine grained control over the URI to be built if needed. The dummy method invocations handled to ….linkTo(…) now transparently adds the values handed in for parameters annotated with @RequestParam.

Most of the commit is highly inspired by Dietrich Schultens work at [0]. I just reworked and polished it slightly as we had too many merge conflicts due to related changes in the meantime.

[0] 1ebdc9025a
This commit is contained in:
Oliver Gierke
2013-02-23 22:26:23 +01:00
parent d152bcb7d1
commit 84efebc7a6
4 changed files with 127 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2013 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.
@@ -21,7 +21,6 @@ import org.springframework.hateoas.Identifiable;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkBuilder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
@@ -60,8 +59,14 @@ public abstract class LinkBuilderSupport<T extends LinkBuilder> implements LinkB
return slash((Identifiable<?>) object);
}
String[] segments = StringUtils.tokenizeToStringArray(object.toString(), "/");
return createNewInstance(UriComponentsBuilder.fromUri(uriComponents.toUri()).pathSegment(segments));
UriComponents components = UriComponentsBuilder.fromUriString(object.toString()).build();
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(uriComponents.toUri());
for (String pathSegment : components.getPathSegments()) {
builder.pathSegment(pathSegment);
}
return createNewInstance(builder.query(components.getQuery()));
}
/*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2013 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.
@@ -152,6 +152,15 @@ public class ControllerLinkBuilder extends LinkBuilderSupport<ControllerLinkBuil
return new ControllerLinkBuilder(builder);
}
/**
* Returns a {@link UriComponentsBuilder} to continue to build the already built URI in a more fine grained way.
*
* @return
*/
public UriComponentsBuilder toUriComponentsBuilder() {
return UriComponentsBuilder.fromUri(toUri());
}
/**
* Returns a {@link UriComponentsBuilder} obtained from the current servlet mapping with the host tweaked in case the
* request contains an {@code X-Forwarded-Host} header.

View File

@@ -16,14 +16,15 @@
package org.springframework.hateoas.mvc;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.MethodParameter;
@@ -38,6 +39,7 @@ import org.springframework.hateoas.core.MethodParameters;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriTemplate;
@@ -50,8 +52,10 @@ import org.springframework.web.util.UriTemplate;
public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory<ControllerLinkBuilder> {
private static final MappingDiscoverer DISCOVERER = new AnnotationMappingDiscoverer(RequestMapping.class);
private static final AnnotatedParametersParameterAccessor ACCESSOR = new AnnotatedParametersParameterAccessor(
private static final AnnotatedParametersParameterAccessor PATH_VARIABLE_ACCESSOR = new AnnotatedParametersParameterAccessor(
new AnnotationAttribute(PathVariable.class));
private static final AnnotatedParametersParameterAccessor REQUEST_PARAM_ACCESSOR = new AnnotatedParametersParameterAccessor(
new AnnotationAttribute(RequestParam.class));
private List<UriComponentsContributor> uriComponentsContributors = new ArrayList<UriComponentsContributor>();
@@ -107,11 +111,24 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory<Co
}
}
values.putAll(ACCESSOR.getBoundParameters(invocation));
URI uri = template.expand(values);
values.putAll(PATH_VARIABLE_ACCESSOR.getBoundParameters(invocation));
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(template.expand(values));
UriComponentsBuilder builder = ControllerLinkBuilder.getBuilder();
return new ControllerLinkBuilder(applyUriComponentsContributer(builder, invocation)).slash(uri);
for (Entry<String, Object> param : REQUEST_PARAM_ACCESSOR.getBoundParameters(invocation).entrySet()) {
Object value = param.getValue();
String key = param.getKey();
if (value instanceof Collection) {
for (Object element : (Collection<?>) value) {
builder.queryParam(key, element);
}
} else {
builder.queryParam(key, value);
}
}
return new ControllerLinkBuilder(applyUriComponentsContributer(builder, invocation));
}
/*