diff --git a/src/main/java/org/springframework/hateoas/Links.java b/src/main/java/org/springframework/hateoas/Links.java
index 63caeaec..9f2bf82a 100644
--- a/src/main/java/org/springframework/hateoas/Links.java
+++ b/src/main/java/org/springframework/hateoas/Links.java
@@ -76,7 +76,7 @@ public class Links implements Iterable {
* @param links
*/
public static Links of(Iterable links) {
- return new Links(links);
+ return Links.class.isInstance(links) ? Links.class.cast(links) : new Links(links);
}
/**
@@ -134,6 +134,26 @@ public class Links implements Iterable {
return and(Arrays.asList(links));
}
+ /**
+ * Adds the given links if the given condition is {@literal true}. The given {@link Link}s will only be resolved if
+ * the given condition is {@literal true}. Essentially syntactic sugar to write:
+ *
+ * if (a > 3) {
+ * links = links.and(…);
+ * }
+ * as
+ * links = link.andIf(a > 3, …);
+ *
+ *
+ * @param condition
+ * @param links must not be {@literal null}.
+ * @return
+ */
+ @SafeVarargs
+ public final Links andIf(boolean condition, Link... links) {
+ return condition ? and(links) : this;
+ }
+
/**
* Adds the given links if the given condition is {@literal true}. The given {@link Supplier}s will only be resolved
* if the given condition is {@literal true}. Essentially syntactic sugar to write:
diff --git a/src/test/java/org/springframework/hateoas/LinksUnitTest.java b/src/test/java/org/springframework/hateoas/LinksUnitTest.java
index 43f4f7ec..b45b424a 100755
--- a/src/test/java/org/springframework/hateoas/LinksUnitTest.java
+++ b/src/test/java/org/springframework/hateoas/LinksUnitTest.java
@@ -143,12 +143,31 @@ class LinksUnitTest {
assertThat(Links.of(first, second).containsSameLinksAs(Links.of(first, second))).isTrue();
}
- @Test // #1322
- void conditionallyAddsLink() {
+ @TestFactory // #1322, #1341
+ Stream conditionallyAddsLink() {
- Links links = Links.NONE.andIf(true, () -> Link.of("/foo"));
+ Links links = Links.NONE;
+ Link link = Link.of("/foo");
- assertThat(links.getRequiredLink(IanaLinkRelations.SELF).getHref()).isEqualTo("/foo");
+ List adders = Arrays.asList(//
+ NamedLinks.of("adds via varargs", links.andIf(true, link)), //
+ NamedLinks.of("adds via Supplier", links.andIf(true, () -> link)), //
+ NamedLinks.of("adds via Stream", links.andIf(true, Stream.of(link))));
+
+ Stream adderTests = DynamicTest.stream(adders.iterator(), NamedLinks::getName, it -> {
+ assertThat(it.links.getRequiredLink(IanaLinkRelations.SELF).getHref()).isEqualTo("/foo");
+ });
+
+ List nonAdders = Arrays.asList(//
+ NamedLinks.of("does not add via varargs", links.andIf(false, link)), //
+ NamedLinks.of("does not add via Supplier", links.andIf(false, () -> link)), //
+ NamedLinks.of("does not add via Stream", links.andIf(false, Stream.of(link))));
+
+ Stream nonAdderTests = DynamicTest.stream(nonAdders.iterator(), NamedLinks::getName, it -> {
+ assertThat(it.links).isEmpty();
+ });
+
+ return Stream.concat(adderTests, nonAdderTests);
}
@Test // #1322
@@ -192,6 +211,52 @@ class LinksUnitTest {
.element(0).extracting(Link::getHref).isEqualTo("/foo"));
}
+ @TestFactory // #1340
+ Stream replacesLinksViaMerge() {
+
+ Links links = Links.of(Link.of("/foo"));
+ Link sameRel = Link.of("/bar");
+
+ List sources = Arrays.asList(//
+ NamedLinks.of("replace same rel via varargs", links.merge(MergeMode.REPLACE_BY_REL, sameRel)),
+ NamedLinks.of("replace same rel via Stream", links.merge(MergeMode.REPLACE_BY_REL, Stream.of(sameRel))));
+
+ return DynamicTest.stream(sources.iterator(), NamedLinks::getName,
+ it -> assertThat(it.links).hasSize(1) //
+ .element(0).extracting(Link::getHref).isEqualTo("/bar"));
+ }
+
+ @Test
+ void removesLinkByRel() {
+ assertThat(Links.of(Link.of("/foo")).without(IanaLinkRelations.SELF)).isEmpty();
+ }
+
+ @Test
+ void basics() {
+
+ Links none = Links.NONE;
+
+ assertThat(none.isEmpty()).isTrue();
+ assertThat(none.stream()).isEmpty();
+ assertThat(none.hasSingleLink()).isFalse();
+ assertThat(none.hasSize(0)).isTrue();
+ assertThat(none.hasLink("self")).isFalse();
+
+ Links one = none.and(Link.of("/foo"));
+
+ assertThat(one.isEmpty()).isFalse();
+ assertThat(one.stream()).isNotEmpty();
+ assertThat(one.hasSingleLink()).isTrue();
+ assertThat(one.hasSize(1)).isTrue();
+ assertThat(one.hasLink("self")).isTrue();
+
+ Links anotherOne = none.and(Link.of("/foo"));
+
+ assertThat(anotherOne).isEqualTo(one);
+ assertThat(one).isEqualTo(anotherOne);
+ assertThat(one.hashCode()).isEqualTo(anotherOne.hashCode());
+ }
+
@Value(staticConstructor = "of")
static class NamedLinks {
String name;