#977 - Performance improvements in link generation.
Introduced more caches for reusable value objects: UriTemplate, MethodParameters. Cache UriTemplate.toString() to avoid re-computation. Avoid recomputing the affordances if possible in WebHandler. Removed cache in AnnotatedParametersParameterAccessor as that one now transitively benefits from the one introduced in MethodParameters. Related ticket: spring-projects/spring-framework#22730.
This commit is contained in:
@@ -118,7 +118,7 @@ public class Link implements Serializable {
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
*/
|
||||
public Link(String href, String rel) {
|
||||
this(new UriTemplate(href), LinkRelation.of(rel));
|
||||
this(UriTemplate.of(href), LinkRelation.of(rel));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +128,7 @@ public class Link implements Serializable {
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
*/
|
||||
public Link(String href, LinkRelation rel) {
|
||||
this(new UriTemplate(href), rel);
|
||||
this(UriTemplate.of(href), rel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,7 +299,7 @@ public class Link implements Serializable {
|
||||
*/
|
||||
@JsonIgnore
|
||||
public List<String> getVariableNames() {
|
||||
return getUriTemplate().getVariableNames();
|
||||
return template.getVariableNames();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,7 +309,7 @@ public class Link implements Serializable {
|
||||
*/
|
||||
@JsonIgnore
|
||||
public List<TemplateVariable> getVariables() {
|
||||
return getUriTemplate().getVariables();
|
||||
return template.getVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -318,7 +318,7 @@ public class Link implements Serializable {
|
||||
* @return
|
||||
*/
|
||||
public boolean isTemplated() {
|
||||
return !getUriTemplate().getVariables().isEmpty();
|
||||
return !template.getVariables().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,7 +328,7 @@ public class Link implements Serializable {
|
||||
* @return
|
||||
*/
|
||||
public Link expand(Object... arguments) {
|
||||
return new Link(getUriTemplate().expand(arguments).toString(), getRel());
|
||||
return new Link(template.expand(arguments).toString(), getRel());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +338,7 @@ public class Link implements Serializable {
|
||||
* @return
|
||||
*/
|
||||
public Link expand(Map<String, ? extends Object> arguments) {
|
||||
return new Link(getUriTemplate().expand(arguments).toString(), getRel());
|
||||
return new Link(template.expand(arguments).toString(), getRel());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,15 +390,6 @@ public class Link implements Serializable {
|
||||
return this.rel.isSameAs(rel);
|
||||
}
|
||||
|
||||
private UriTemplate getUriTemplate() {
|
||||
|
||||
if (this.template == null) {
|
||||
this.template = new UriTemplate(href);
|
||||
}
|
||||
|
||||
return this.template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current href as URI after expanding the links without any arguments, i.e. all optional URI
|
||||
* {@link TemplateVariable}s will be dropped. If the href contains mandatory {@link TemplateVariable}s, the URI
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -46,7 +47,10 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
private static final Pattern VARIABLE_REGEX = Pattern.compile("\\{([\\?\\&#/]?)([\\w\\,*]+)\\}");
|
||||
private static final long serialVersionUID = -1007874653930162262L;
|
||||
|
||||
private static final Map<String, UriTemplate> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final TemplateVariables variables;
|
||||
private String toString;
|
||||
private String baseUri;
|
||||
|
||||
/**
|
||||
@@ -54,7 +58,7 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
*
|
||||
* @param template must not be {@literal null} or empty.
|
||||
*/
|
||||
public UriTemplate(String template) {
|
||||
private UriTemplate(String template) {
|
||||
|
||||
Assert.hasText(template, "Template must not be null or empty!");
|
||||
|
||||
@@ -97,7 +101,7 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
* @param baseUri must not be {@literal null} or empty.
|
||||
* @param variables must not be {@literal null}.
|
||||
*/
|
||||
public UriTemplate(String baseUri, TemplateVariables variables) {
|
||||
UriTemplate(String baseUri, TemplateVariables variables) {
|
||||
|
||||
Assert.hasText(baseUri, "Base URI must not be null or empty!");
|
||||
Assert.notNull(variables, "Template variables must not be null!");
|
||||
@@ -106,6 +110,19 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link UriTemplate} for the given {@link String} template.
|
||||
*
|
||||
* @param template must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public static UriTemplate of(String template) {
|
||||
|
||||
Assert.hasText(template, "Template must not be null or empty!");
|
||||
|
||||
return CACHE.computeIfAbsent(template, UriTemplate::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link UriTemplate} with the current {@link TemplateVariable}s augmented with the given ones.
|
||||
*
|
||||
@@ -267,10 +284,15 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
UriComponents components = UriComponentsBuilder.fromUriString(baseUri).build();
|
||||
boolean hasQueryParameters = !components.getQueryParams().isEmpty();
|
||||
if (toString == null) {
|
||||
|
||||
return baseUri + getOptionalVariables().toString(hasQueryParameters);
|
||||
UriComponents components = UriComponentsBuilder.fromUriString(baseUri).build();
|
||||
boolean hasQueryParameters = !components.getQueryParams().isEmpty();
|
||||
|
||||
this.toString = baseUri + getOptionalVariables().toString(hasQueryParameters);
|
||||
}
|
||||
|
||||
return toString;
|
||||
}
|
||||
|
||||
private TemplateVariables getOptionalVariables() {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.hateoas.client;
|
||||
|
||||
import static org.springframework.http.HttpMethod.GET;
|
||||
import static org.springframework.http.HttpMethod.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
@@ -385,15 +385,14 @@ public class Traverson {
|
||||
|
||||
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), rels.iterator(), HttpHeaders.EMPTY);
|
||||
|
||||
return new UriStringAndHeaders(new UriTemplate(uriAndHeaders.getUri()).toString(),
|
||||
uriAndHeaders.getHttpHeaders());
|
||||
return new UriStringAndHeaders(UriTemplate.of(uriAndHeaders.getUri()).toString(), uriAndHeaders.getHttpHeaders());
|
||||
}
|
||||
|
||||
private URIAndHeaders traverseToExpandedFinalUrl() {
|
||||
|
||||
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), rels.iterator(), HttpHeaders.EMPTY);
|
||||
|
||||
return new URIAndHeaders(new UriTemplate(uriAndHeaders.getUri()).expand(templateParameters),
|
||||
return new URIAndHeaders(UriTemplate.of(uriAndHeaders.getUri()).expand(templateParameters),
|
||||
uriAndHeaders.getHttpHeaders());
|
||||
}
|
||||
|
||||
@@ -404,7 +403,7 @@ public class Traverson {
|
||||
}
|
||||
|
||||
HttpEntity<?> request = prepareRequest(mergeHeaders(this.headers, extraHeaders));
|
||||
URI target = new UriTemplate(uri).expand();
|
||||
URI target = UriTemplate.of(uri).expand();
|
||||
|
||||
ResponseEntity<String> responseEntity = operations.exchange(target, GET, request, String.class);
|
||||
MediaType contentType = responseEntity.getHeaders().getContentType();
|
||||
|
||||
@@ -38,7 +38,8 @@ import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
*/
|
||||
public class MethodParameters {
|
||||
|
||||
private static ParameterNameDiscoverer DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
private static final ParameterNameDiscoverer DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
private static final Map<Method, MethodParameters> CACHE = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private final List<MethodParameter> parameters;
|
||||
private final Map<Class<?>, List<MethodParameter>> parametersWithAnnotationCache = new ConcurrentReferenceHashMap<>();
|
||||
@@ -48,10 +49,23 @@ public class MethodParameters {
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
*/
|
||||
public MethodParameters(Method method) {
|
||||
private MethodParameters(Method method) {
|
||||
this(method, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MethodParameters} for the given {@link Method}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static MethodParameters of(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
|
||||
return CACHE.computeIfAbsent(method, MethodParameters::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MethodParameters} for the given {@link Method} and {@link AnnotationAttribute}. If the latter
|
||||
* is given, method parameter names will be looked up from the annotation attribute if present.
|
||||
@@ -115,14 +129,15 @@ public class MethodParameters {
|
||||
* @param annotation must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<MethodParameter> getParametersWith(Class<? extends Annotation> annotation) {
|
||||
|
||||
Assert.notNull(annotation, "Annotation must not be null!");
|
||||
|
||||
return parametersWithAnnotationCache.computeIfAbsent(annotation, key -> {
|
||||
|
||||
Assert.notNull(annotation, "Annotation must not be null!");
|
||||
|
||||
return getParameters().stream()//
|
||||
.filter(it -> it.hasParameterAnnotation(annotation))//
|
||||
.filter(it -> it.hasParameterAnnotation((Class<? extends Annotation>) key))//
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.hateoas.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -26,10 +26,8 @@ import org.springframework.hateoas.AffordanceModelFactory;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkRelation;
|
||||
import org.springframework.hateoas.QueryParameter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
|
||||
/**
|
||||
* Extract information needed to assemble an {@link Affordance} from a Spring MVC web method.
|
||||
@@ -43,44 +41,34 @@ public class SpringAffordanceBuilder {
|
||||
* Use the attributes of the current method call along with a collection of {@link AffordanceModelFactory}'s to create
|
||||
* a set of {@link Affordance}s.
|
||||
*
|
||||
* @param invocation
|
||||
* @param discoverer
|
||||
* @param components
|
||||
* @param type must not be {@literal null}.
|
||||
* @param method must not be {@literal null}.
|
||||
* @param href must not be {@literal null}.
|
||||
* @param discoverer must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static List<Affordance> create(MethodInvocation invocation, MappingDiscoverer discoverer,
|
||||
UriComponents components) {
|
||||
public static List<Affordance> create(Class<?> type, Method method, String href, MappingDiscoverer discoverer) {
|
||||
|
||||
List<Affordance> affordances = new ArrayList<>();
|
||||
String methodName = method.getName();
|
||||
Link affordanceLink = new Link(href, LinkRelation.of(methodName));
|
||||
|
||||
for (HttpMethod requestMethod : discoverer.getRequestMethod(invocation.getTargetType(), invocation.getMethod())) {
|
||||
MethodParameters parameters = MethodParameters.of(method);
|
||||
|
||||
String methodName = invocation.getMethod().getName();
|
||||
ResolvableType inputType = parameters.getParametersWith(RequestBody.class).stream() //
|
||||
.findFirst() //
|
||||
.map(ResolvableType::forMethodParameter) //
|
||||
.orElse(ResolvableType.NONE);
|
||||
|
||||
String href = components.toUriString().equals("") ? "/" : components.toUriString();
|
||||
Link affordanceLink = new Link(href).withRel(LinkRelation.of(methodName));
|
||||
List<QueryParameter> queryMethodParameters = parameters.getParametersWith(RequestParam.class).stream() //
|
||||
.map(it -> it.getParameterAnnotation(RequestParam.class)) //
|
||||
.filter(Objects::nonNull) //
|
||||
.map(it -> new QueryParameter(it.name(), it.value(), it.required())) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
MethodParameters invocationMethodParameters = new MethodParameters(invocation.getMethod());
|
||||
ResolvableType outputType = ResolvableType.forMethodReturnType(method);
|
||||
|
||||
ResolvableType inputType = invocationMethodParameters.getParametersWith(RequestBody.class).stream() //
|
||||
.findFirst() //
|
||||
.map(ResolvableType::forMethodParameter) //
|
||||
.orElse(ResolvableType.NONE);
|
||||
|
||||
List<QueryParameter> queryMethodParameters = invocationMethodParameters.getParametersWith(RequestParam.class)
|
||||
.stream() //
|
||||
.map(methodParameter -> methodParameter.getParameterAnnotation(RequestParam.class)) //
|
||||
.filter(Objects::nonNull) //
|
||||
.map(requestParam -> new QueryParameter(requestParam.name(), requestParam.value(), requestParam.required())) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ResolvableType outputType = ResolvableType.forMethodReturnType(invocation.getMethod());
|
||||
|
||||
affordances
|
||||
.add(new Affordance(methodName, affordanceLink, requestMethod, inputType, queryMethodParameters, outputType));
|
||||
|
||||
}
|
||||
|
||||
return affordances;
|
||||
return discoverer.getRequestMethod(type, method).stream() //
|
||||
.map(it -> new Affordance(methodName, affordanceLink, it, inputType, queryMethodParameters, outputType)) //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.springframework.web.util.UriComponents.UriTemplateVariables.*;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -70,6 +71,8 @@ public class WebHandler {
|
||||
private static final AnnotatedParametersParameterAccessor REQUEST_PARAM_ACCESSOR //
|
||||
= new RequestParamParameterAccessor();
|
||||
|
||||
private static final Map<AffordanceKey, List<Affordance>> AFFORDANCES_CACHE = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
public interface LinkBuilderCreator<T extends LinkBuilder> {
|
||||
T createBuilder(UriComponents components, TemplateVariables variables, List<Affordance> affordances);
|
||||
}
|
||||
@@ -89,6 +92,7 @@ public class WebHandler {
|
||||
MethodInvocation invocation = invocations.getLastInvocation();
|
||||
|
||||
return mappingToUriComponentsBuilder -> {
|
||||
|
||||
String mapping = DISCOVERER.getMapping(invocation.getTargetType(), invocation.getMethod());
|
||||
|
||||
UriComponentsBuilder builder = mappingToUriComponentsBuilder.apply(mapping);
|
||||
@@ -145,7 +149,11 @@ public class WebHandler {
|
||||
variables = variables.concat(variable);
|
||||
}
|
||||
|
||||
List<Affordance> affordances = SpringAffordanceBuilder.create(invocation, DISCOVERER, components);
|
||||
String href = components.toUriString().equals("") ? "/" : components.toUriString();
|
||||
|
||||
List<Affordance> affordances = AFFORDANCES_CACHE.computeIfAbsent(
|
||||
AffordanceKey.of(invocation.getTargetType(), invocation.getMethod(), href),
|
||||
key -> SpringAffordanceBuilder.create(key.type, key.method, key.href, DISCOVERER));
|
||||
|
||||
return creator.createBuilder(components, variables, affordances);
|
||||
};
|
||||
@@ -280,9 +288,6 @@ public class WebHandler {
|
||||
@RequiredArgsConstructor
|
||||
private static class AnnotatedParametersParameterAccessor {
|
||||
|
||||
private static final Map<Method, MethodParameters> METHOD_PARAMETERS_CACHE = new ConcurrentReferenceHashMap<>(16,
|
||||
ConcurrentReferenceHashMap.ReferenceType.WEAK);
|
||||
|
||||
private final @NonNull AnnotationAttribute attribute;
|
||||
|
||||
/**
|
||||
@@ -295,7 +300,7 @@ public class WebHandler {
|
||||
|
||||
Assert.notNull(invocation, "MethodInvocation must not be null!");
|
||||
|
||||
MethodParameters parameters = getOrCreateMethodParametersFor(invocation.getMethod());
|
||||
MethodParameters parameters = MethodParameters.of(invocation.getMethod());
|
||||
Object[] arguments = invocation.getArguments();
|
||||
List<BoundMethodParameter> result = new ArrayList<>();
|
||||
|
||||
@@ -339,16 +344,6 @@ public class WebHandler {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MethodParameters} for the given {@link Method}.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
private static MethodParameters getOrCreateMethodParametersFor(Method method) {
|
||||
return METHOD_PARAMETERS_CACHE.computeIfAbsent(method, MethodParameters::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a {@link MethodParameter} alongside the value it has been bound to.
|
||||
*
|
||||
@@ -442,4 +437,12 @@ public class WebHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Value(staticConstructor = "of")
|
||||
private static class AffordanceKey {
|
||||
|
||||
Class<?> type;
|
||||
Method method;
|
||||
String href;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory<Co
|
||||
|
||||
return WebHandler.linkTo(invocationValue, ControllerLinkBuilder::new, (builder, invocation) -> {
|
||||
|
||||
MethodParameters parameters = new MethodParameters(invocation.getMethod());
|
||||
MethodParameters parameters = MethodParameters.of(invocation.getMethod());
|
||||
Iterator<Object> parameterValues = Arrays.asList(invocation.getArguments()).iterator();
|
||||
|
||||
for (MethodParameter parameter : parameters.getParameters()) {
|
||||
|
||||
@@ -108,7 +108,7 @@ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory<WebMvc
|
||||
|
||||
return WebHandler.linkTo(invocationValue, WebMvcLinkBuilder::new, (builder, invocation) -> {
|
||||
|
||||
MethodParameters parameters = new MethodParameters(invocation.getMethod());
|
||||
MethodParameters parameters = MethodParameters.of(invocation.getMethod());
|
||||
Iterator<Object> parameterValues = Arrays.asList(invocation.getArguments()).iterator();
|
||||
|
||||
for (MethodParameter parameter : parameters.getParameters()) {
|
||||
|
||||
@@ -55,7 +55,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void discoversRequestParam() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{?bar}");
|
||||
UriTemplate template = UriTemplate.of("/foo{?bar}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("bar", VariableType.REQUEST_PARAM));
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void discoversRequestParamCntinued() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo?bar{&foobar}");
|
||||
UriTemplate template = UriTemplate.of("/foo?bar{&foobar}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("foobar", VariableType.REQUEST_PARAM_CONTINUED));
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void discoversOptionalPathVariable() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{/bar}");
|
||||
UriTemplate template = UriTemplate.of("/foo{/bar}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("bar", VariableType.SEGMENT));
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void discoversPathVariable() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo/{bar}");
|
||||
UriTemplate template = UriTemplate.of("/foo/{bar}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("bar", VariableType.PATH_VARIABLE));
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void discoversFragment() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{#bar}");
|
||||
UriTemplate template = UriTemplate.of("/foo{#bar}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("bar", VariableType.FRAGMENT));
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void discoversMultipleRequestParam() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{?bar,foobar}");
|
||||
UriTemplate template = UriTemplate.of("/foo{?bar,foobar}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("bar", VariableType.REQUEST_PARAM),
|
||||
new TemplateVariable("foobar", VariableType.REQUEST_PARAM));
|
||||
@@ -122,7 +122,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void expandsRequestParameter() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{?bar}");
|
||||
UriTemplate template = UriTemplate.of("/foo{?bar}");
|
||||
|
||||
URI uri = template.expand(Collections.singletonMap("bar", "myBar"));
|
||||
assertThat(uri.toString()).isEqualTo("/foo?bar=myBar");
|
||||
@@ -138,7 +138,7 @@ public class UriTemplateUnitTest {
|
||||
parameters.put("bar", "myBar");
|
||||
parameters.put("fooBar", "myFooBar");
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{?bar,fooBar}");
|
||||
UriTemplate template = UriTemplate.of("/foo{?bar,fooBar}");
|
||||
|
||||
URI uri = template.expand(parameters);
|
||||
assertThat(uri.toString()).isEqualTo("/foo?bar=myBar&fooBar=myFooBar");
|
||||
@@ -150,7 +150,7 @@ public class UriTemplateUnitTest {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsMissingRequiredPathVariable() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo/{bar}");
|
||||
UriTemplate template = UriTemplate.of("/foo/{bar}");
|
||||
template.expand(Collections.emptyMap());
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void expandsMultipleVariablesViaArray() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{/bar}{?firstname,lastname}{#anchor}");
|
||||
UriTemplate template = UriTemplate.of("/foo{/bar}{?firstname,lastname}{#anchor}");
|
||||
URI uri = template.expand("path", "Dave", "Matthews", "discography");
|
||||
assertThat(uri.toString()).isEqualTo("/foo/path?firstname=Dave&lastname=Matthews#discography");
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class UriTemplateUnitTest {
|
||||
*/
|
||||
@Test
|
||||
public void expandsTemplateWithoutVariablesCorrectly() {
|
||||
assertThat(new UriTemplate("/foo").expand().toString()).isEqualTo("/foo");
|
||||
assertThat(UriTemplate.of("/foo").expand().toString()).isEqualTo("/foo");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +178,7 @@ public class UriTemplateUnitTest {
|
||||
*/
|
||||
@Test
|
||||
public void correctlyExpandsFullUri() {
|
||||
assertThat(new UriTemplate("http://localhost:8080/foo{?bar}").expand().toString())
|
||||
assertThat(UriTemplate.of("http://localhost:8080/foo{?bar}").expand().toString())
|
||||
.isEqualTo("http://localhost:8080/foo");
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void rendersUriTempalteWithPathVariable() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/{foo}/bar{?page}");
|
||||
UriTemplate template = UriTemplate.of("/{foo}/bar{?page}");
|
||||
assertThat(template.toString()).isEqualTo("/{foo}/bar{?page}");
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void addsTemplateVariables() {
|
||||
|
||||
UriTemplate source = new UriTemplate("/{foo}/bar{?page}");
|
||||
UriTemplate source = UriTemplate.of("/{foo}/bar{?page}");
|
||||
List<TemplateVariable> toAdd = Arrays.asList(new TemplateVariable("bar", VariableType.REQUEST_PARAM));
|
||||
|
||||
List<TemplateVariable> expected = new ArrayList<>();
|
||||
@@ -214,7 +214,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void doesNotAddVariablesForAlreadyExistingRequestParameters() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/?page=2");
|
||||
UriTemplate template = UriTemplate.of("/?page=2");
|
||||
UriTemplate result = template.with(new TemplateVariables(new TemplateVariable("page", VariableType.REQUEST_PARAM)));
|
||||
assertThat(result.getVariableNames()).isEmpty();
|
||||
|
||||
@@ -228,7 +228,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void doesNotAddVariablesForAlreadyExistingFragment() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/#fragment");
|
||||
UriTemplate template = UriTemplate.of("/#fragment");
|
||||
UriTemplate result = template.with(new TemplateVariables(new TemplateVariable("fragment", VariableType.FRAGMENT)));
|
||||
assertThat(result.getVariableNames()).isEmpty();
|
||||
}
|
||||
@@ -239,7 +239,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void expandASimplePathVariable() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo/{id}");
|
||||
UriTemplate template = UriTemplate.of("/foo/{id}");
|
||||
assertThat(template.expand(2).toString()).isEqualTo("/foo/2");
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void allowsAddingTemplateVariable() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/").with("q", VariableType.REQUEST_PARAM);
|
||||
UriTemplate template = UriTemplate.of("/").with("q", VariableType.REQUEST_PARAM);
|
||||
|
||||
assertThat(template.toString()).isEqualTo("/{?q}");
|
||||
}
|
||||
@@ -268,7 +268,7 @@ public class UriTemplateUnitTest {
|
||||
@Test
|
||||
public void compositveValuesAreRecognisedAsVariableType() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{&bar,foobar*}");
|
||||
UriTemplate template = UriTemplate.of("/foo{&bar,foobar*}");
|
||||
|
||||
assertVariables(template, new TemplateVariable("bar", VariableType.REQUEST_PARAM_CONTINUED),
|
||||
new TemplateVariable("foobar", VariableType.COMPOSITE_PARAM));
|
||||
@@ -281,7 +281,7 @@ public class UriTemplateUnitTest {
|
||||
@SuppressWarnings("serial")
|
||||
public void expandsCompositeValueAsAssociativeArray() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{&bar,foobar*}");
|
||||
UriTemplate template = UriTemplate.of("/foo{&bar,foobar*}");
|
||||
|
||||
String expandedTemplate = template.expand(new HashMap<String, Object>() {
|
||||
{
|
||||
@@ -305,7 +305,7 @@ public class UriTemplateUnitTest {
|
||||
@SuppressWarnings("serial")
|
||||
public void expandsCompositeValueAsList() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{&bar,foobar*}");
|
||||
UriTemplate template = UriTemplate.of("/foo{&bar,foobar*}");
|
||||
|
||||
String expandedTemplate = template.expand(new HashMap<String, Object>() {
|
||||
{
|
||||
@@ -324,7 +324,7 @@ public class UriTemplateUnitTest {
|
||||
@SuppressWarnings("serial")
|
||||
public void handlesCompositeValueAsSingleValue() {
|
||||
|
||||
UriTemplate template = new UriTemplate("/foo{&bar,foobar*}");
|
||||
UriTemplate template = UriTemplate.of("/foo{&bar,foobar*}");
|
||||
|
||||
String expandedTemplate = template.expand(new HashMap<String, Object>() {
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
*/
|
||||
public class DefaultCurieProviderUnitTest {
|
||||
|
||||
private static final UriTemplate URI_TEMPLATE = new UriTemplate("http://localhost:8080/rels/{rel}");
|
||||
private static final UriTemplate URI_TEMPLATE = UriTemplate.of("http://localhost:8080/rels/{rel}");
|
||||
|
||||
CurieProvider provider = new DefaultCurieProvider("acme", URI_TEMPLATE);
|
||||
|
||||
@@ -63,12 +63,12 @@ public class DefaultCurieProviderUnitTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void preventsUriTemplateWithoutVariable() {
|
||||
new DefaultCurieProvider("acme", new UriTemplate("http://localhost:8080/rels"));
|
||||
new DefaultCurieProvider("acme", UriTemplate.of("http://localhost:8080/rels"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void preventsUriTemplateWithMoreThanOneVariable() {
|
||||
new DefaultCurieProvider("acme", new UriTemplate("http://localhost:8080/rels/{rel}/{another}"));
|
||||
new DefaultCurieProvider("acme", UriTemplate.of("http://localhost:8080/rels/{rel}/{another}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -170,7 +170,7 @@ public class DefaultCurieProviderUnitTest {
|
||||
@Test
|
||||
public void expandsNonAbsoluteUriWithApplicationUri() {
|
||||
|
||||
DefaultCurieProvider provider = new DefaultCurieProvider("name", new UriTemplate("/docs/{rel}"));
|
||||
DefaultCurieProvider provider = new DefaultCurieProvider("name", UriTemplate.of("/docs/{rel}"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
|
||||
@@ -189,8 +189,8 @@ public class DefaultCurieProviderUnitTest {
|
||||
private static Map<String, UriTemplate> getCuries() {
|
||||
|
||||
Map<String, UriTemplate> curies = new HashMap<>(2);
|
||||
curies.put("foo", new UriTemplate("/foo/{rel}"));
|
||||
curies.put("bar", new UriTemplate("/bar/{rel}"));
|
||||
curies.put("foo", UriTemplate.of("/foo/{rel}"));
|
||||
curies.put("bar", UriTemplate.of("/bar/{rel}"));
|
||||
|
||||
return curies;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class HalEmbeddedBuilderUnitTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
provider = new EvoInflectorLinkRelationProvider();
|
||||
curieProvider = new DefaultCurieProvider("curie", new UriTemplate("http://localhost/{rel}"));
|
||||
curieProvider = new DefaultCurieProvider("curie", UriTemplate.of("http://localhost/{rel}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -403,7 +403,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
|
||||
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
|
||||
resources.add(new Link("foo", "myrel"));
|
||||
|
||||
CurieProvider provider = new DefaultCurieProvider("default", new UriTemplate("/doc{?rel}")) {
|
||||
CurieProvider provider = new DefaultCurieProvider("default", UriTemplate.of("/doc{?rel}")) {
|
||||
@Override
|
||||
public Collection<? extends Object> getCurieInformation(Links links) {
|
||||
return Arrays.asList(new Curie("foo", "bar"), new Curie("bar", "foo"));
|
||||
@@ -538,7 +538,7 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
|
||||
}
|
||||
|
||||
private ObjectMapper getCuriedObjectMapper() {
|
||||
return getCuriedObjectMapper(new DefaultCurieProvider("foo", new UriTemplate("http://localhost:8080/rels/{rel}")));
|
||||
return getCuriedObjectMapper(new DefaultCurieProvider("foo", UriTemplate.of("http://localhost:8080/rels/{rel}")));
|
||||
}
|
||||
|
||||
private ObjectMapper getCuriedObjectMapper(CurieProvider provider) {
|
||||
|
||||
@@ -338,7 +338,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
|
||||
CollectionModel<Object> resources = new CollectionModel<>(Collections.emptySet());
|
||||
resources.add(new Link("foo", "myrel"));
|
||||
|
||||
CurieProvider provider = new DefaultCurieProvider("default", new UriTemplate("/doc{?rel}")) {
|
||||
CurieProvider provider = new DefaultCurieProvider("default", UriTemplate.of("/doc{?rel}")) {
|
||||
@Override
|
||||
public Collection<?> getCurieInformation(Links links) {
|
||||
return Arrays.asList(new Curie("foo", "bar"), new Curie("bar", "foo"));
|
||||
@@ -438,7 +438,7 @@ public class Jackson2HalFormsIntegrationTest extends AbstractJackson2Marshalling
|
||||
|
||||
private ObjectMapper getCuriedObjectMapper() {
|
||||
|
||||
return getCuriedObjectMapper(new DefaultCurieProvider("foo", new UriTemplate("http://localhost:8080/rels/{rel}")),
|
||||
return getCuriedObjectMapper(new DefaultCurieProvider("foo", UriTemplate.of("http://localhost:8080/rels/{rel}")),
|
||||
messageSource);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.core.MethodParameter;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MethodParameters}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class MethodParametersUnitTest {
|
||||
@@ -49,7 +49,7 @@ public class MethodParametersUnitTest {
|
||||
public void returnsParametersOfAGivenType() throws Exception {
|
||||
|
||||
Method method = Sample.class.getMethod("method", String.class, String.class, Object.class);
|
||||
MethodParameters methodParameters = new MethodParameters(method);
|
||||
MethodParameters methodParameters = MethodParameters.of(method);
|
||||
|
||||
List<MethodParameter> objectParameters = methodParameters.getParametersOfType(Object.class);
|
||||
assertThat(objectParameters).hasSize(1);
|
||||
|
||||
@@ -74,12 +74,12 @@ public class PropertyUtilsTest {
|
||||
public void resourceWrappedSpringMvcParameter() {
|
||||
|
||||
Method method = ReflectionUtils.findMethod(TestController.class, "newEmployee", EntityModel.class);
|
||||
MethodParameters parameters = new MethodParameters(method);
|
||||
MethodParameters parameters = MethodParameters.of(method);
|
||||
|
||||
ResolvableType resolvableType = parameters.getParametersWith(RequestBody.class).stream()
|
||||
.findFirst()
|
||||
.map(methodParameter -> ResolvableType.forMethodParameter(methodParameter.getMethod(), methodParameter.getParameterIndex()))
|
||||
.orElseThrow(() -> new RuntimeException("Didn't find a parameter annotated with @RequestBody!"));
|
||||
ResolvableType resolvableType = parameters.getParametersWith(RequestBody.class).stream().findFirst()
|
||||
.map(methodParameter -> ResolvableType.forMethodParameter(methodParameter.getMethod(),
|
||||
methodParameter.getParameterIndex()))
|
||||
.orElseThrow(() -> new RuntimeException("Didn't find a parameter annotated with @RequestBody!"));
|
||||
|
||||
List<String> propertyNames = PropertyUtils.findPropertyNames(resolvableType);
|
||||
|
||||
@@ -90,19 +90,18 @@ public class PropertyUtilsTest {
|
||||
@Test
|
||||
public void objectWithIgnorableAttributes() {
|
||||
|
||||
EmployeeWithCustomizedReaders employee = new EmployeeWithCustomizedReaders("Frodo", "Baggins", "ring bearer", "password", "fbaggins", "ignore this one");
|
||||
EmployeeWithCustomizedReaders employee = new EmployeeWithCustomizedReaders("Frodo", "Baggins", "ring bearer",
|
||||
"password", "fbaggins", "ignore this one");
|
||||
|
||||
Map<String, Object> properties = PropertyUtils.findProperties(employee);
|
||||
|
||||
assertThat(properties).hasSize(6);
|
||||
assertThat(properties.keySet()).containsExactlyInAnyOrder("firstName", "lastName", "role", "username", "fullName", "usernameAndLastName");
|
||||
assertThat(properties.entrySet()).containsExactlyInAnyOrder(
|
||||
new SimpleEntry<>("firstName", "Frodo"),
|
||||
new SimpleEntry<>("lastName", "Baggins"),
|
||||
new SimpleEntry<>("role", "ring bearer"),
|
||||
new SimpleEntry<>("username", "fbaggins"),
|
||||
new SimpleEntry<>("fullName", "Frodo Baggins"),
|
||||
new SimpleEntry<>("usernameAndLastName", "fbaggins+++Baggins"));
|
||||
assertThat(properties.keySet()).containsExactlyInAnyOrder("firstName", "lastName", "role", "username", "fullName",
|
||||
"usernameAndLastName");
|
||||
assertThat(properties.entrySet()).containsExactlyInAnyOrder(new SimpleEntry<>("firstName", "Frodo"),
|
||||
new SimpleEntry<>("lastName", "Baggins"), new SimpleEntry<>("role", "ring bearer"),
|
||||
new SimpleEntry<>("username", "fbaggins"), new SimpleEntry<>("fullName", "Frodo Baggins"),
|
||||
new SimpleEntry<>("usernameAndLastName", "fbaggins+++Baggins"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,14 +113,13 @@ public class PropertyUtilsTest {
|
||||
|
||||
assertThat(properties).hasSize(2);
|
||||
assertThat(properties.keySet()).containsExactlyInAnyOrder("name", "father");
|
||||
assertThat(properties.entrySet()).containsExactlyInAnyOrder(
|
||||
new SimpleEntry<>("name", "Frodo"),
|
||||
new SimpleEntry<>("father", null));
|
||||
assertThat(properties.entrySet()).containsExactlyInAnyOrder(new SimpleEntry<>("name", "Frodo"),
|
||||
new SimpleEntry<>("father", null));
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@JsonIgnoreProperties({"ignoreThisProperty"})
|
||||
@JsonIgnoreProperties({ "ignoreThisProperty" })
|
||||
static class EmployeeWithCustomizedReaders {
|
||||
|
||||
private String firstName;
|
||||
@@ -159,12 +157,11 @@ public class PropertyUtilsTest {
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
|
||||
@GetMapping("/")
|
||||
public Employee newEmployee(@RequestBody EntityModel<Employee> employee) {
|
||||
return employee.getContent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user