#743 - Polishing.

This commit is contained in:
Greg Turnquist
2018-10-25 11:38:39 -05:00
parent b60799d7fa
commit df618efd12
3 changed files with 164 additions and 120 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2018 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.
@@ -33,6 +33,7 @@ import org.springframework.util.Assert;
*
* @author Greg Turnquist
* @author Oliver Gierke
* @author Manish Misra
* @since 0.18
*/
@Value
@@ -50,6 +51,9 @@ public class Hop {
*/
private final @Wither Map<String, Object> parameters;
/**
* Extra {@link HttpHeaders} to apply to this hop.
*/
private final @Wither HttpHeaders headers;
/**
@@ -62,7 +66,7 @@ public class Hop {
Assert.hasText(rel, "Relation must not be null or empty!");
return new Hop(rel, Collections.<String, Object> emptyMap(), null);
return new Hop(rel, Collections.emptyMap(), HttpHeaders.EMPTY);
}
/**
@@ -76,13 +80,10 @@ public class Hop {
Assert.hasText(name, "Name must not be null or empty!");
HashMap<String, Object> parameters = new HashMap<String, Object>(this.parameters);
HashMap<String, Object> parameters = new HashMap<>(this.parameters);
parameters.put(name, value);
if (this.hasHeaders())
return new Hop(rel, parameters, this.headers);
else
return new Hop(rel, parameters, null);
return new Hop(this.rel, parameters, this.headers);
}
/**
@@ -92,20 +93,21 @@ public class Hop {
* @param headerValue can be {@literal null}.
* @return
*/
public Hop withHeader(String headerName, String headerValue){
Assert.notNull(headers, "Headers must not be null!");
public Hop header(String headerName, String headerValue) {
HttpHeaders headers = new HttpHeaders();
Assert.notNull(headerName, "headerName must not be null!");
Assert.notNull(headerValue, "headerValue must not be null!");
if(this.hasHeaders())
headers.addAll(this.headers);
if (this.headers == HttpHeaders.EMPTY) {
headers.add(headerName, headerValue);
HttpHeaders newHeaders = new HttpHeaders();
newHeaders.add(headerName, headerValue);
if(this.hasParameters())
return new Hop(rel, this.parameters, headers);
else
return new Hop(rel, Collections.<String, Object> emptyMap(), headers);
return new Hop(this.rel, this.parameters, newHeaders);
}
this.headers.add(headerName, headerValue);
return this;
}
/**
@@ -117,15 +119,6 @@ public class Hop {
return !this.parameters.isEmpty();
}
/**
* Returns whether the {@link Hop} has headers declared.
*
* @return
*/
boolean hasHeaders() {
return this.headers != null && !this.headers.isEmpty();
}
/**
* Create a new {@link Map} starting with the supplied template parameters. Then add the ones for this hop. This
* allows a local hop to override global parameters.
@@ -144,20 +137,4 @@ public class Hop {
return mergedParameters;
}
/**
* Create a new {@link Map} starting with the supplied headers. Then add the ones for this hop. This
* allows a local hop to override global headers.
*
* @param globalHeaders must not be {@literal null}.
* @return
*/
HttpHeaders getMergedHeaders(HttpHeaders globalHeaders){
Assert.notNull(globalHeaders, "Global Headers must not be null!");
if(this.hasHeaders())
globalHeaders.addAll(this.headers);
return globalHeaders;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2018 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.
@@ -17,6 +17,9 @@ package org.springframework.hateoas.client;
import static org.springframework.http.HttpMethod.*;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -28,7 +31,6 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.sun.jndi.toolkit.url.Uri;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkDiscoverer;
@@ -63,6 +65,7 @@ import com.jayway.jsonpath.JsonPath;
* @author Dietrich Schulten
* @author Greg Turnquist
* @author Tom Bunting
* @author Manish Misra
* @since 0.11
*/
public class Traverson {
@@ -191,7 +194,7 @@ public class Traverson {
*/
public Traverson setRestOperations(RestOperations operations) {
this.operations = operations == null ? createDefaultTemplate(mediaTypes) : operations;
this.operations = operations == null ? createDefaultTemplate(this.mediaTypes) : operations;
return this;
}
@@ -204,7 +207,7 @@ public class Traverson {
*/
public Traverson setLinkDiscoverers(List<? extends LinkDiscoverer> discoverer) {
this.discoverers = discoverers == null ? DEFAULT_LINK_DISCOVERERS
this.discoverers = this.discoverers == null ? DEFAULT_LINK_DISCOVERERS
: new LinkDiscoverers(OrderAwarePluginRegistry.create(discoverer));
return this;
@@ -300,6 +303,8 @@ public class Traverson {
*/
public TraversalBuilder withTemplateParameters(Map<String, Object> parameters) {
Assert.notNull(parameters, "Parameters must not be null!");
this.templateParameters = parameters;
return this;
}
@@ -312,6 +317,8 @@ public class Traverson {
*/
public TraversalBuilder withHeaders(HttpHeaders headers) {
Assert.notNull(headers, "Headers must not be null!");
this.headers = headers;
return this;
}
@@ -326,8 +333,10 @@ public class Traverson {
Assert.notNull(type, "Target type must not be null!");
LinkWithHeader linkWithHeader = traverseToExpandedFinalUrl();
return operations.exchange(linkWithHeader.uriAsURI, GET, prepareRequest(linkWithHeader.httpHeaders), type).getBody();
URIAndHeaders uriAndHeaders = traverseToExpandedFinalUrl();
HttpEntity<?> requestEntity = prepareRequest(mergeHeaders(this.headers, uriAndHeaders.getHttpHeaders()));
return operations.exchange(uriAndHeaders.getUri(), GET, requestEntity, type).getBody();
}
/**
@@ -341,8 +350,10 @@ public class Traverson {
Assert.notNull(type, "Target type must not be null!");
LinkWithHeader linkWithHeader = traverseToExpandedFinalUrl();
return operations.exchange(linkWithHeader.uriAsURI, GET, prepareRequest(linkWithHeader.httpHeaders), type).getBody();
URIAndHeaders uriAndHeaders = traverseToExpandedFinalUrl();
HttpEntity<?> requestEntity = prepareRequest(mergeHeaders(this.headers, uriAndHeaders.getHttpHeaders()));
return operations.exchange(uriAndHeaders.getUri(), GET, requestEntity, type).getBody();
}
/**
@@ -356,9 +367,10 @@ public class Traverson {
Assert.hasText(jsonPath, "JSON path must not be null or empty!");
LinkWithHeader linkWithHeader = traverseToExpandedFinalUrl();
String forObject = operations.exchange(linkWithHeader.uriAsURI, GET, prepareRequest(linkWithHeader.httpHeaders), String.class)
.getBody();
URIAndHeaders uriAndHeaders = traverseToExpandedFinalUrl();
HttpEntity<?> requestEntity = prepareRequest(mergeHeaders(this.headers, uriAndHeaders.getHttpHeaders()));
String forObject = operations.exchange(uriAndHeaders.getUri(), GET, requestEntity, String.class).getBody();
return JsonPath.read(forObject, jsonPath);
}
@@ -371,8 +383,11 @@ public class Traverson {
public <T> ResponseEntity<T> toEntity(Class<T> type) {
Assert.notNull(type, "Target type must not be null!");
LinkWithHeader linkWithHeader = traverseToExpandedFinalUrl();
return operations.exchange(linkWithHeader.uriAsURI, GET, prepareRequest(linkWithHeader.httpHeaders), type);
URIAndHeaders uriAndHeaders = traverseToExpandedFinalUrl();
HttpEntity<?> requestEntity = prepareRequest(mergeHeaders(this.headers, uriAndHeaders.getHttpHeaders()));
return operations.exchange(uriAndHeaders.getUri(), GET, requestEntity, type);
}
/**
@@ -399,28 +414,34 @@ public class Traverson {
private Link traverseToLink(boolean expandFinalUrl) {
Assert.isTrue(rels.size() > 0, "At least one rel needs to be provided!");
return new Link(expandFinalUrl ? traverseToExpandedFinalUrl().uriAsURI.toString() : traverseToFinalUrl(),
rels.get(rels.size() - 1).getRel());
Assert.isTrue(this.rels.size() > 0, "At least one rel needs to be provided!");
URIAndHeaders expandedFinalUriAndHeaders = traverseToExpandedFinalUrl();
UriStringAndHeaders finalUriAndHeaders = traverseToFinalUrl();
return new Link(expandFinalUrl ? expandedFinalUriAndHeaders.getUri().toString() : finalUriAndHeaders.getUri(),
this.rels.get(this.rels.size() - 1).getRel());
}
private String traverseToFinalUrl() {
private UriStringAndHeaders traverseToFinalUrl() {
return getAndFindLinkWithRel(baseUri.toString(), rels.iterator(), headers).uriAsString;
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), this.rels.iterator(), HttpHeaders.EMPTY);
return new UriStringAndHeaders(new UriTemplate(uriAndHeaders.getUri()).toString(), uriAndHeaders.getHttpHeaders());
}
private LinkWithHeader traverseToExpandedFinalUrl() {
private URIAndHeaders traverseToExpandedFinalUrl() {
return getAndFindLinkWithRel(baseUri.toString(), rels.iterator(), headers);
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), this.rels.iterator(), HttpHeaders.EMPTY);
return new URIAndHeaders(new UriTemplate(uriAndHeaders.getUri()).expand(this.templateParameters), uriAndHeaders.getHttpHeaders());
}
private LinkWithHeader getAndFindLinkWithRel(String uri, Iterator<Hop> rels, HttpHeaders headers) {
private UriStringAndHeaders getAndFindLinkWithRel(String uri, Iterator<Hop> rels, HttpHeaders extraHeaders) {
if (!rels.hasNext()) {
return new LinkWithHeader(uri, headers);
return new UriStringAndHeaders(uri, extraHeaders);
}
HttpEntity<?> request = prepareRequest(headers);
HttpEntity<?> request = prepareRequest(mergeHeaders(this.headers, extraHeaders));
UriTemplate template = new UriTemplate(uri);
ResponseEntity<String> responseEntity = operations.exchange(template.expand(), GET, request, String.class);
@@ -437,50 +458,53 @@ public class Traverson {
String.format("Expected to find link with rel '%s' in response %s!", rel, responseBody));
}
/**
/*
* Don't expand if the parameters are empty
*/
if (!thisHop.hasParameters()) {
return getAndFindLinkWithRel(link.getHref(), rels, thisHop.getMergedHeaders(this.headers));
return getAndFindLinkWithRel(link.getHref(), rels, thisHop.getHeaders());
} else {
return getAndFindLinkWithRel(link.expand(thisHop.getMergedParameters(templateParameters)).getHref(), rels, thisHop.getMergedHeaders(this.headers));
return getAndFindLinkWithRel(link.expand(thisHop.getMergedParameters(this.templateParameters)).getHref(), rels, thisHop.getHeaders());
}
}
private class LinkWithHeader{
private String uriAsString;
private URI uriAsURI;
private HttpHeaders httpHeaders;
/**
* Combine two sets of {@link HttpHeaders} into one.
*
* @param headersA
* @param headersB
* @return
*/
private HttpHeaders mergeHeaders(HttpHeaders headersA, HttpHeaders headersB) {
LinkWithHeader(String uri, HttpHeaders httpHeaders){
this.uriAsString = new UriTemplate(uri).toString();
this.uriAsURI = new UriTemplate(uri).expand(templateParameters);
this.httpHeaders = httpHeaders;
}
HttpHeaders mergedHeaders = new HttpHeaders();
public URI getUriAsURI() {
return uriAsURI;
}
mergedHeaders.addAll(headersA);
mergedHeaders.addAll(headersB);
public void setUriAsURI(URI uriAsURI) {
this.uriAsURI = uriAsURI;
}
public String getUriAsString() {
return uriAsString;
}
public void setUriAsString(String uriAsString) {
this.uriAsString = uriAsString;
}
public HttpHeaders getHttpHeaders() {
return httpHeaders;
}
public void setHttpHeaders(HttpHeaders httpHeaders) {
this.httpHeaders = httpHeaders;
}
return mergedHeaders;
}
}
/**
* Temporary container for a string-base {@literal URI} and {@link HttpHeaders}.
*/
@Value
@RequiredArgsConstructor
private static class UriStringAndHeaders {
private final String uri;
private final HttpHeaders httpHeaders;
}
/**
* Temporary container for a {@link URI}-based {@literal URI} and {@link HttpHeaders}.
*/
@Value
@RequiredArgsConstructor
private static class URIAndHeaders {
private final URI uri;
private final HttpHeaders httpHeaders;
}
}