#831 - Polishing.

Significant rework of the nullability annotation introduction to not produce any warnings anymore. Added nullability annotations where still missing. Removed the ones that were added erroneously.

Tightened nullability contracts in a couple of places, most prominently LinkRelationProvider, that now uses a LookupContext as plugin delimiter so that implementations can selectively be looked up for item or collection link relation lookup.

Removed obsolete declaration of Findbugs dependency.
This commit is contained in:
Oliver Drotbohm
2019-03-19 23:41:08 +01:00
parent fdee61fde7
commit 75ad0988cd
78 changed files with 1224 additions and 626 deletions

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.hateoas.client;
import net.minidev.json.JSONArray;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@@ -25,11 +27,11 @@ import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minidev.json.JSONArray;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import com.jayway.jsonpath.InvalidPathException;
@@ -124,7 +126,7 @@ public class JsonPathLinkDiscoverer implements LinkDiscoverer {
* @see org.springframework.plugin.core.Plugin#supports(java.lang.Object)
*/
@Override
public boolean supports(MediaType delimiter) {
public boolean supports(@NonNull MediaType delimiter) {
return this.mediaTypes.stream() //
.anyMatch(mediaType -> mediaType.isCompatibleWith(delimiter));

View File

@@ -57,11 +57,11 @@ class Rels {
/**
* Returns the link contained in the given representation of the given {@link MediaType}.
*
* @param representation
* @param mediaType
* @param representation will never be {@literal null}.
* @param mediaType will never be {@literal null}.
* @return
*/
Optional<Link> findInResponse(@Nullable String representation, @Nullable MediaType mediaType);
Optional<Link> findInResponse(String representation, MediaType mediaType);
}
/**

View File

@@ -207,6 +207,9 @@ public class Traverson {
*/
public class TraversalBuilder {
private static final String MEDIA_TYPE_HEADER_NOT_FOUND = "Response for request to %s did not expose a content type! Unable to identify links!";
private static final String LINK_NOT_FOUND = "Expected to find link with rel '%s' in response %s!";
private final List<Hop> rels = new ArrayList<>();
private Map<String, Object> templateParameters = new HashMap<>();
private HttpHeaders headers = new HttpHeaders();
@@ -224,9 +227,9 @@ public class Traverson {
Assert.notNull(rels, "Rels must not be null!");
for (String rel : rels) {
this.rels.add(Hop.rel(rel));
}
Arrays.stream(rels) //
.map(Hop::rel) //
.forEach(this.rels::add);
return this;
}
@@ -327,6 +330,7 @@ public class Traverson {
HttpEntity<?> requestEntity = prepareRequest(mergeHeaders(this.headers, uriAndHeaders.getHttpHeaders()));
String forObject = operations.exchange(uriAndHeaders.getUri(), GET, requestEntity, String.class).getBody();
return JsonPath.read(forObject, jsonPath);
}
@@ -359,7 +363,7 @@ public class Traverson {
}
/**
* Returns the templated {@link Link} found for the last rel in the rels configured to follow.
* Returns the templated {@link Link} found for the last relation in the rels configured to follow.
*
* @return
* @since 0.17
@@ -370,28 +374,28 @@ public class Traverson {
private Link traverseToLink(boolean expandFinalUrl) {
Assert.isTrue(this.rels.size() > 0, "At least one rel needs to be provided!");
Assert.isTrue(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());
rels.get(rels.size() - 1).getRel());
}
private UriStringAndHeaders traverseToFinalUrl() {
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), this.rels.iterator(),
HttpHeaders.EMPTY);
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), rels.iterator(), HttpHeaders.EMPTY);
return new UriStringAndHeaders(new UriTemplate(uriAndHeaders.getUri()).toString(),
uriAndHeaders.getHttpHeaders());
}
private URIAndHeaders traverseToExpandedFinalUrl() {
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), this.rels.iterator(),
HttpHeaders.EMPTY);
return new URIAndHeaders(new UriTemplate(uriAndHeaders.getUri()).expand(this.templateParameters),
UriStringAndHeaders uriAndHeaders = getAndFindLinkWithRel(baseUri.toString(), rels.iterator(), HttpHeaders.EMPTY);
return new URIAndHeaders(new UriTemplate(uriAndHeaders.getUri()).expand(templateParameters),
uriAndHeaders.getHttpHeaders());
}
@@ -402,28 +406,28 @@ public class Traverson {
}
HttpEntity<?> request = prepareRequest(mergeHeaders(this.headers, extraHeaders));
UriTemplate template = new UriTemplate(uri);
URI target = new UriTemplate(uri).expand();
ResponseEntity<String> responseEntity = operations.exchange(template.expand(), GET, request, String.class);
ResponseEntity<String> responseEntity = operations.exchange(target, GET, request, String.class);
MediaType contentType = responseEntity.getHeaders().getContentType();
if (contentType == null) {
throw new IllegalStateException(String.format(MEDIA_TYPE_HEADER_NOT_FOUND, target));
}
String responseBody = responseEntity.getBody();
Hop thisHop = rels.next();
Rel rel = Rels.getRelFor(thisHop.getRel(), discoverers);
Link link = rel.findInResponse(responseBody, contentType) //
.orElseThrow(() -> new IllegalStateException(
String.format("Expected to find link with rel '%s' in response %s!", rel, responseBody)));
Link link = rel.findInResponse(responseBody == null ? "" : responseBody, contentType) //
.orElseThrow(() -> new IllegalStateException(String.format(LINK_NOT_FOUND, rel, responseBody)));
/*
* Don't expand if the parameters are empty
*/
if (!thisHop.hasParameters()) {
return getAndFindLinkWithRel(link.getHref(), rels, thisHop.getHeaders());
} else {
return getAndFindLinkWithRel(link.expand(thisHop.getMergedParameters(this.templateParameters)).getHref(), rels,
thisHop.getHeaders());
}
String linkTarget = thisHop.hasParameters() //
? link.expand(thisHop.getMergedParameters(templateParameters)).getHref() //
: link.getHref();
return getAndFindLinkWithRel(linkTarget, rels, thisHop.getHeaders());
}
/**

View File

@@ -1,7 +1,5 @@
/**
* Client side support.
*/
@NonNullApi
@org.springframework.lang.NonNullApi
package org.springframework.hateoas.client;
import org.springframework.lang.NonNullApi;