Derive a link's description from its title
Previously, a LinkDescriptor had to be created with both a rel and a description. If a description was not provided a failure would occur. This commit relaxes the above-described restriction by allowing a link's title to be used as its default description. If a descriptor has a description, it will always be used irrespective of whether or not the link has a title. If the descriptor does not have a description and the link does have a title, the link's title will be used. If the descriptor does not have a description and the link does not have a title a failure will occur. Closes gh-105
This commit is contained in:
@@ -51,7 +51,9 @@ class AtomLinkExtractor extends AbstractJsonLinkExtractor {
|
||||
Object hrefObject = linkMap.get("href");
|
||||
Object relObject = linkMap.get("rel");
|
||||
if (relObject instanceof String && hrefObject instanceof String) {
|
||||
return new Link((String) relObject, (String) hrefObject);
|
||||
Object titleObject = linkMap.get("title");
|
||||
return new Link((String) relObject, (String) hrefObject,
|
||||
titleObject instanceof String ? (String) titleObject : null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -67,9 +67,12 @@ class HalLinkExtractor extends AbstractJsonLinkExtractor {
|
||||
|
||||
private static Link maybeCreateLink(String rel, Object possibleLinkObject) {
|
||||
if (possibleLinkObject instanceof Map) {
|
||||
Object hrefObject = ((Map<?, ?>) possibleLinkObject).get("href");
|
||||
Map<?, ?> possibleLinkMap = (Map<?, ?>) possibleLinkObject;
|
||||
Object hrefObject = possibleLinkMap.get("href");
|
||||
if (hrefObject instanceof String) {
|
||||
return new Link(rel, (String) hrefObject);
|
||||
Object titleObject = possibleLinkMap.get("title");
|
||||
return new Link(rel, (String) hrefObject,
|
||||
titleObject instanceof String ? (String) titleObject : null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -53,6 +53,10 @@ public abstract class HypermediaDocumentation {
|
||||
* If you do not want to document a link, a link descriptor can be marked as
|
||||
* {@link LinkDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
* <p>
|
||||
* If a descriptor does not have a {@link LinkDescriptor#description(Object)
|
||||
* description}, the {@link Link#getTitle() title} of the link will be used. If the
|
||||
* link does not have a title a failure will occur.
|
||||
*
|
||||
* @param descriptors the descriptions of the response's links
|
||||
* @return the snippet that will document the links
|
||||
|
||||
@@ -29,6 +29,8 @@ public class Link {
|
||||
|
||||
private final String href;
|
||||
|
||||
private final String title;
|
||||
|
||||
/**
|
||||
* Creates a new {@code Link} with the given {@code rel} and {@code href}.
|
||||
*
|
||||
@@ -36,8 +38,21 @@ public class Link {
|
||||
* @param href The link's href
|
||||
*/
|
||||
public Link(String rel, String href) {
|
||||
this(rel, href, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Link} with the given {@code rel}, {@code href}, and
|
||||
* {@code title}.
|
||||
*
|
||||
* @param rel The link's rel
|
||||
* @param href The link's href
|
||||
* @param title The link's title
|
||||
*/
|
||||
public Link(String rel, String href, String title) {
|
||||
this.rel = rel;
|
||||
this.href = href;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,12 +71,21 @@ public class Link {
|
||||
return this.href;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the link's {@code title}, or {@code null} if it does not have a title.
|
||||
* @return the link's {@code title} or {@code null}
|
||||
*/
|
||||
public String getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int prime = 31;
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + this.href.hashCode();
|
||||
result = prime * result + this.rel.hashCode();
|
||||
result = prime * result + ((this.title == null) ? 0 : this.title.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -83,13 +107,21 @@ public class Link {
|
||||
if (!this.rel.equals(other.rel)) {
|
||||
return false;
|
||||
}
|
||||
if (this.title == null) {
|
||||
if (other.title != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!this.title.equals(other.title)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("rel", this.rel).append("href", this.href)
|
||||
.toString();
|
||||
.append("title", this.title).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,12 +77,6 @@ public class LinksSnippet extends TemplatedSnippet {
|
||||
this.linkExtractor = linkExtractor;
|
||||
for (LinkDescriptor descriptor : descriptors) {
|
||||
Assert.notNull(descriptor.getRel(), "Link descriptors must have a rel");
|
||||
if (!descriptor.isIgnored()) {
|
||||
Assert.notNull(descriptor.getDescription(),
|
||||
"The descriptor for link '" + descriptor.getRel()
|
||||
+ "' must either have a description or be" + " marked as "
|
||||
+ "ignored");
|
||||
}
|
||||
this.descriptorsByRel.put(descriptor.getRel(), descriptor);
|
||||
}
|
||||
}
|
||||
@@ -90,14 +84,16 @@ public class LinksSnippet extends TemplatedSnippet {
|
||||
@Override
|
||||
protected Map<String, Object> createModel(Operation operation) {
|
||||
OperationResponse response = operation.getResponse();
|
||||
Map<String, List<Link>> links;
|
||||
try {
|
||||
validate(this.linkExtractor.extractLinks(response));
|
||||
links = this.linkExtractor.extractLinks(response);
|
||||
validate(links);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ModelCreationException(ex);
|
||||
}
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
model.put("links", createLinksModel());
|
||||
model.put("links", createLinksModel(links));
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -135,17 +131,48 @@ public class LinksSnippet extends TemplatedSnippet {
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> createLinksModel() {
|
||||
private List<Map<String, Object>> createLinksModel(Map<String, List<Link>> links) {
|
||||
List<Map<String, Object>> model = new ArrayList<>();
|
||||
for (Entry<String, LinkDescriptor> entry : this.descriptorsByRel.entrySet()) {
|
||||
LinkDescriptor descriptor = entry.getValue();
|
||||
if (!descriptor.isIgnored()) {
|
||||
if (descriptor.getDescription() == null) {
|
||||
descriptor = createDescriptor(
|
||||
getDescriptionFromLinkTitle(links, descriptor.getRel()),
|
||||
descriptor);
|
||||
}
|
||||
model.add(createModelForDescriptor(descriptor));
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
private String getDescriptionFromLinkTitle(Map<String, List<Link>> links,
|
||||
String rel) {
|
||||
List<Link> linksForRel = links.get(rel);
|
||||
if (linksForRel != null) {
|
||||
for (Link link : linksForRel) {
|
||||
if (link.getTitle() != null) {
|
||||
return link.getTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new SnippetException("No description was provided for the link with rel '"
|
||||
+ rel + "' and no title was available from the link in the payload");
|
||||
}
|
||||
|
||||
private LinkDescriptor createDescriptor(String description, LinkDescriptor source) {
|
||||
LinkDescriptor newDescriptor = new LinkDescriptor(source.getRel())
|
||||
.description(description);
|
||||
if (source.isOptional()) {
|
||||
newDescriptor.optional();
|
||||
}
|
||||
if (source.isIgnored()) {
|
||||
newDescriptor.ignored();
|
||||
}
|
||||
return newDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Map} of {@link LinkDescriptor LinkDescriptors} keyed by their
|
||||
* {@link LinkDescriptor#getRel() rels}.
|
||||
|
||||
Reference in New Issue
Block a user