Skip to content

Commit

Permalink
Removing duplicate curies from embedded objects if embedding
Browse files Browse the repository at this point in the history
HalRepresentation already specifies the curi. Closes #22
  • Loading branch information
gsteinacker committed May 2, 2018
1 parent 99fd26d commit 2af0c6c
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 13 deletions.
20 changes: 17 additions & 3 deletions src/main/java/de/otto/edison/hal/HalRepresentation.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.JsonNode;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
import static de.otto.edison.hal.Curies.emptyCuries;
import static de.otto.edison.hal.Embedded.Builder.copyOf;
import static de.otto.edison.hal.Embedded.emptyEmbedded;
import static de.otto.edison.hal.Links.copyOf;
import static de.otto.edison.hal.Links.emptyLinks;
import static de.otto.edison.hal.Curies.emptyCuries;

/**
* Representation used to parse and create HAL+JSON documents from Java classes.
Expand Down Expand Up @@ -230,8 +231,11 @@ protected HalRepresentation withEmbedded(final String rel, final HalRepresentati
*/
HalRepresentation mergeWithEmbedding(final Curies curies) {
this.curies = this.curies.mergeWith(curies);
if (links != null) {
links = links.using(curies);
if (this.links != null) {

removeDuplicateCuriesFromEmbedding(curies);

this.links = this.links.using(this.curies);
if (embedded != null) {
embedded = embedded.using(this.curies);
}
Expand All @@ -243,6 +247,16 @@ HalRepresentation mergeWithEmbedding(final Curies curies) {
return this;
}

private void removeDuplicateCuriesFromEmbedding(final Curies curies) {
if (this.links.hasLink("curies")) {
final List<Link> curiLinks = new ArrayList<>(this.links.getLinksBy("curies"));
curies.getCuries().forEach(curi -> {
curiLinks.removeIf((link -> link.isEquivalentTo(curi)));
});
this.links = copyOf(this.links).replace("curies", curiLinks).build();
}
}

/**
* {@inheritDoc}
*
Expand Down
36 changes: 35 additions & 1 deletion src/main/java/de/otto/edison/hal/Links.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import java.util.function.Predicate;
import java.util.stream.Stream;

import static de.otto.edison.hal.Link.linkBuilder;
import static de.otto.edison.hal.Curies.emptyCuries;
import static de.otto.edison.hal.Link.linkBuilder;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
Expand Down Expand Up @@ -597,6 +597,40 @@ public Builder array(final List<Link> links) {
return this;
}

/**
* Replaces the link(s) currently associated with {@code rel} by a list of links to the builder that will be
* rendered as an array of link-objects.
* <p>
* All links must have the {@link Link#getRel() Link-Relation Type} specified in {@code rel}, otherwise
* an {@link IllegalArgumentException} is thrown.
* </p>
* <p>
* As specified in <a href="https://tools.ietf.org/html/draft-kelly-json-hal-06#section-4.1.1">Section 4.1.1</a>
* of the HAL specification, the {@code _links} object <em>"is an object whose property names are
* link relation types (as defined by [RFC5988]) and values are either a Link Object or an array
* of Link Objects"</em>.
* </p>
* <p>
* Replacing links using {@code replace(List<Link>)} will result in a representation, where the links are
* rendered as an array of Link Objects, even if there are only single links for a given Link-Relation Type.
* </p>
*
* @param links the list of links.
* @return this
*
* @since 2.0.0
*/
public Builder replace(final String rel, final List<Link> links) {
if (!links.stream().allMatch(link -> link.getRel().equals(rel))) {
throw new IllegalArgumentException("All links must have link-relation type " + rel);
}
if (!this.links.containsKey(rel)) {
return array(links);
}
this.links.replace(rel, links);
return this;
}

/**
* Adds all links from {@link Links} to the builder.
* <p>
Expand Down
20 changes: 17 additions & 3 deletions src/test/java/de/otto/edison/hal/HalRepresentationCuriesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static de.otto.edison.hal.Curies.curies;
import static de.otto.edison.hal.Embedded.embedded;
import static de.otto.edison.hal.Embedded.emptyEmbedded;
import static de.otto.edison.hal.Link.curi;
import static de.otto.edison.hal.Link.link;
import static de.otto.edison.hal.Links.emptyLinks;
import static de.otto.edison.hal.Links.linkingTo;
import static de.otto.edison.hal.Curies.curies;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.*;

public class HalRepresentationCuriesTest {

Expand Down Expand Up @@ -113,4 +112,19 @@ public void shouldInheritCuries() {
assertThat(embeddedHal.getCuries().resolve("http://example.com/rels/foo"), is("x:foo"));
}

@Test
public void shouldRemoveDuplicateCuries() {
// given
final HalRepresentation embeddedHal = new HalRepresentation(linkingTo().curi("x", "http://example.com/rels/{rel}").build());
final HalRepresentation representation = new HalRepresentation(linkingTo().curi("x", "http://example.com/rels/{rel}").build(), embedded("http://example.com/rels/foo", singletonList(embeddedHal)));
// when
final HalRepresentation embeddedAfterCreation = representation.getEmbedded().getItemsBy("x:foo").get(0);
// then
assertThat(embeddedAfterCreation.getCuries().resolve("http://example.com/rels/foo"), is("x:foo"));
assertThat(embeddedAfterCreation.getLinks().getLinksBy("curies"), is(empty()));
assertThat(representation.getLinks().getLinksBy("curies"), contains(curi("x", "http://example.com/rels/{rel}")));
// but
assertThat(embeddedHal.getLinks().getLinksBy("curies"), is(empty()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.*;

public class HalRepresentationEmbeddingTest {

Expand Down Expand Up @@ -186,7 +185,61 @@ public void shouldUseCuriesInEmbedded() throws JsonProcessingException {
}

@Test
public void shouldUseCuriesInSingleEmbedded() throws JsonProcessingException {
public void shouldRemoveDuplicateCuriesFromEmbedded() {
// given
final List<HalRepresentation> items = asList(
new HalRepresentation(linkingTo()
.self("http://example.org/test/bar/01")
.curi("x", "http://example.org/rels/{rel}")
.build()),
new HalRepresentation(linkingTo()
.self("http://example.org/test/bar/02")
.curi("x", "http://example.org/rels/{rel}")
.build())
);
// when
final HalRepresentation representation = new HalRepresentation(
linkingTo()
.curi("x", "http://example.org/rels/{rel}").build(),
embedded("x:orders", items)) {};
// then
List<HalRepresentation> embeddedItems = representation.getEmbedded().getItemsBy("x:orders");
assertThat(embeddedItems, hasSize(2));
embeddedItems.forEach(item -> {
assertThat(item.getLinks().getLinkBy("curies").isPresent(), is(false));
});
}

@Test
public void shouldRemoveDuplicateCuriesFromEmbeddedUsingWithEmbedded() {
// given
final List<HalRepresentation> items = asList(
new HalRepresentation(linkingTo()
.self("http://example.org/test/bar/01")
.curi("x", "http://example.org/rels/{rel}")
.build()),
new HalRepresentation(linkingTo()
.self("http://example.org/test/bar/02")
.curi("x", "http://example.org/rels/{rel}")
.build())
);
// when
final HalRepresentation representation = new HalRepresentation(
linkingTo()
.curi("x", "http://example.org/rels/{rel}").build());

final HalRepresentation embedding = representation.withEmbedded("x:orders", items);

// then
List<HalRepresentation> embeddedItems = embedding.getEmbedded().getItemsBy("x:orders");
assertThat(embeddedItems, hasSize(2));
embeddedItems.forEach(item -> {
assertThat(item.getLinks().getLinkBy("curies").isPresent(), is(false));
});
}

@Test
public void shouldUseCuriesInSingleEmbedded() {
// given
final HalRepresentation item = new HalRepresentation(linkingTo().self("http://example.org/test/bar/01").build());
// when
Expand All @@ -202,7 +255,7 @@ public void shouldUseCuriesInSingleEmbedded() throws JsonProcessingException {
}

@Test
public void shouldUseCuriesByFullRelInEmbedded() throws JsonProcessingException {
public void shouldUseCuriesByFullRelInEmbedded() {
// given
final List<HalRepresentation> items = asList(
new HalRepresentation(linkingTo().self("http://example.org/test/bar/01").build()),
Expand All @@ -218,7 +271,7 @@ public void shouldUseCuriesByFullRelInEmbedded() throws JsonProcessingException
}

@Test
public void shouldUseCuriesInNestedEmbedded() throws JsonProcessingException {
public void shouldUseCuriesInNestedEmbedded() {
// given
final List<HalRepresentation> nestedEmbedded = singletonList(new HalRepresentation(linkingTo().self("http://example.org/test/bar/02").build()));
final List<HalRepresentation> items = singletonList(
Expand All @@ -240,7 +293,7 @@ public void shouldUseCuriesInNestedEmbedded() throws JsonProcessingException {
}

@Test
public void shouldUseCuriesInSingleNestedEmbedded() throws JsonProcessingException {
public void shouldUseCuriesInSingleNestedEmbedded() {
// given
final HalRepresentation nestedEmbedded = new HalRepresentation(linkingTo().self("http://example.org/test/bar/02").build());
final List<HalRepresentation> items = singletonList(
Expand Down

0 comments on commit 2af0c6c

Please sign in to comment.