#653 - Polishing.

Expose nullability in Identifiable, ResourceSupport and Links via Optional.
This commit is contained in:
Oliver Gierke
2017-10-16 17:50:34 +02:00
parent 4c7227e274
commit d9c53b5eeb
9 changed files with 63 additions and 42 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.hateoas;
import java.io.Serializable;
import java.util.Optional;
/**
* Interface to mark objects that are identifiable by an ID of any type.
@@ -27,7 +28,7 @@ public interface Identifiable<ID extends Serializable> {
/**
* Returns the id identifying the object.
*
* @return the identifier or {@literal null} if not available.
* @return the identifier or {@link Optional#empty()} if not available.
*/
ID getId();
Optional<ID> getId();
}

View File

@@ -18,6 +18,7 @@ package org.springframework.hateoas;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@@ -105,7 +106,7 @@ public class PagedResources<T> extends Resources<T> {
* @return
*/
@JsonIgnore
public Link getNextLink() {
public Optional<Link> getNextLink() {
return getLink(Link.REL_NEXT);
}
@@ -115,7 +116,7 @@ public class PagedResources<T> extends Resources<T> {
* @return
*/
@JsonIgnore
public Link getPreviousLink() {
public Optional<Link> getPreviousLink() {
return getLink(Link.REL_PREVIOUS);
}
@@ -251,8 +252,8 @@ public class PagedResources<T> extends Resources<T> {
*/
@Override
public String toString() {
return String.format("Metadata { number: %d, total pages: %d, total elements: %d, size: %d }", number,
totalPages, totalElements, size);
return String.format("Metadata { number: %d, total pages: %d, total elements: %d, size: %d }", number, totalPages,
totalElements, size);
}
/*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2017 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.
@@ -18,7 +18,8 @@ package org.springframework.hateoas;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.xml.bind.annotation.XmlElement;
@@ -37,14 +38,14 @@ public class ResourceSupport implements Identifiable<Link> {
private final List<Link> links;
public ResourceSupport() {
this.links = new ArrayList<>();
this.links = new ArrayList<>();
}
/**
* Returns the {@link Link} with a rel of {@link Link#REL_SELF}.
*/
@JsonIgnore
public Link getId() {
public Optional<Link> getId() {
return getLink(Link.REL_SELF);
}
@@ -65,7 +66,7 @@ public class ResourceSupport implements Identifiable<Link> {
*/
public void add(Iterable<Link> links) {
Assert.notNull(links, "Given links must not be null!");
links.forEach(this::add);
links.forEach(this::add);
}
/**
@@ -94,7 +95,7 @@ public class ResourceSupport implements Identifiable<Link> {
* @return
*/
public boolean hasLink(String rel) {
return getLink(rel) != null;
return getLink(rel).isPresent();
}
/**
@@ -119,13 +120,23 @@ public class ResourceSupport implements Identifiable<Link> {
* Returns the link with the given rel.
*
* @param rel
* @return the link with the given rel or {@literal null} if none found.
* @return the link with the given rel or {@link Optional#empty()} if none found.
*/
public Link getLink(String rel) {
public Optional<Link> getLink(String rel) {
return getLinks(rel).stream().findFirst();
}
return getLinks(rel).stream()
.findFirst()
.orElse(null);
/**
* Returns the link with the given rel.
*
* @param rel
* @return the link with the given rel.
* @throws IllegalArgumentException in case no link with the given rel can be found.
*/
public Link getRequiredLink(String rel) {
return getLink(rel) //
.orElseThrow(() -> new IllegalArgumentException(String.format("No link with rel %s found!", rel)));
}
/**
@@ -135,9 +146,8 @@ public class ResourceSupport implements Identifiable<Link> {
*/
public List<Link> getLinks(String rel) {
return links.stream()
.filter(link -> link.getRel().equals(rel))
.collect(Collectors.toList());
return links.stream() //
.filter(link -> link.getRel().equals(rel)).collect(Collectors.toList());
}
/*

View File

@@ -19,6 +19,7 @@ import static org.springframework.hateoas.core.EncodingUtils.*;
import static org.springframework.web.util.UriComponentsBuilder.*;
import java.net.URI;
import java.util.Optional;
import org.springframework.hateoas.Identifiable;
import org.springframework.hateoas.Link;
@@ -68,6 +69,8 @@ public abstract class LinkBuilderSupport<T extends LinkBuilder> implements LinkB
*/
public T slash(Object object) {
object = Optional.class.isInstance(object) ? ((Optional<?>) object).orElse(null) : object;
if (object == null) {
return getThis();
}

View File

@@ -74,8 +74,8 @@ public class LinksUnitTest {
*/
@Test
public void getSingleLinkByRel() {
assertThat(reference.getLink("bar")).isEqualTo(Optional.of(new Link("/somethingElse", "bar")));
assertThat(reference2.getLink("bar")).isEqualTo(Optional.of(new Link("/somethingElse", "bar").withHreflang("de")));
assertThat(reference.getLink("bar")).hasValue(new Link("/somethingElse", "bar"));
assertThat(reference2.getLink("bar")).hasValue(new Link("/somethingElse", "bar").withHreflang("de"));
}
/**
@@ -90,7 +90,7 @@ public class LinksUnitTest {
Links twoWithCommaInFirst = Links.valueOf(WITH_COMMA.concat(",").concat(SECOND));
assertThat(twoWithCommaInFirst.getLink("foo")).isEqualTo(Optional.of(withComma));
assertThat(twoWithCommaInFirst.getLink("bar")).isEqualTo(Optional.of(new Link("/somethingElse", "bar")));
assertThat(twoWithCommaInFirst.getLink("foo")).hasValue(withComma);
assertThat(twoWithCommaInFirst.getLink("bar")).hasValue(new Link("/somethingElse", "bar"));
}
}

View File

@@ -45,10 +45,10 @@ public class ResourceSupportUnitTest {
ResourceSupport support = new ResourceSupport();
support.add(link);
assertThat(support.getId()).isNull();
assertThat(support.getId()).isEmpty();
assertThat(support.hasLinks()).isTrue();
assertThat(support.hasLink(link.getRel())).isTrue();
assertThat(support.getLink(link.getRel())).isEqualTo(link);
assertThat(support.getLink(link.getRel())).hasValue(link);
assertThat(support.getLinks(Link.REL_NEXT)).contains(link);
}
@@ -75,7 +75,7 @@ public class ResourceSupportUnitTest {
ResourceSupport support = new ResourceSupport();
support.add(Arrays.asList(first, second));
assertThat(support.getId()).isNull();
assertThat(support.getId()).isEmpty();
assertThat(support.hasLinks()).isTrue();
assertThat(support.getLinks()).contains(first, second);
assertThat(support.getLinks()).hasSize(2);
@@ -90,7 +90,7 @@ public class ResourceSupportUnitTest {
ResourceSupport support = new ResourceSupport();
support.add(link);
assertThat(support.getId()).isEqualTo(link);
assertThat(support.getId()).hasValue(link);
}
@Test(expected = IllegalArgumentException.class)

View File

@@ -302,7 +302,7 @@ public class TraversonTest {
// end::hop-with-param[]
assertThat(itemResource.hasLink("self")).isTrue();
assertThat(itemResource.getLink("self").expand().getHref())
assertThat(itemResource.getRequiredLink("self").expand().getHref())
.isEqualTo(server.rootResource() + "/springagram/items/1");
final Item item = itemResource.getContent();
@@ -330,7 +330,7 @@ public class TraversonTest {
// end::hop-put[]
assertThat(itemResource.hasLink("self")).isTrue();
assertThat(itemResource.getLink("self").expand().getHref())
assertThat(itemResource.getRequiredLink("self").expand().getHref())
.isEqualTo(server.rootResource() + "/springagram/items/1");
final Item item = itemResource.getContent();
@@ -355,7 +355,7 @@ public class TraversonTest {
.withTemplateParameters(params).toObject(resourceParameterizedTypeReference);
assertThat(itemResource.hasLink("self")).isTrue();
assertThat(itemResource.getLink("self").expand().getHref())
assertThat(itemResource.getRequiredLink("self").expand().getHref())
.isEqualTo(server.rootResource() + "/springagram/items/1");
final Item item = itemResource.getContent();
@@ -376,7 +376,8 @@ public class TraversonTest {
toObject(Resource.class);
assertThat(itemResource.hasLink("self")).isTrue();
assertThat(itemResource.getLink("self").expand().getHref()).isEqualTo(server.rootResource() + "/springagram/items");
assertThat(itemResource.getRequiredLink("self").expand().getHref())
.isEqualTo(server.rootResource() + "/springagram/items");
}
private void setUpActors() {

View File

@@ -122,7 +122,7 @@ public class ControllerLinkBuilderUnitTest extends TestUtils {
public void usesIdOfIdentifyableForPathSegment() {
Identifiable<Long> identifyable = Mockito.mock(Identifiable.class);
Mockito.when(identifyable.getId()).thenReturn(10L);
Mockito.when(identifyable.getId()).thenReturn(Optional.of(10L));
Link link = linkTo(PersonControllerImpl.class).slash(identifyable).withSelfRel();
assertThat(link.getHref()).endsWith("/people/10");
@@ -599,8 +599,8 @@ public class ControllerLinkBuilderUnitTest extends TestUtils {
Long id;
@Override
public Long getId() {
return id;
public Optional<Long> getId() {
return Optional.ofNullable(id);
}
}

View File

@@ -20,6 +20,7 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
@@ -53,7 +54,7 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
public void createsInstanceWithSelfLinkToController() {
PersonResource resource = assembler.createResource(person);
Link link = resource.getLink(Link.REL_SELF);
Link link = resource.getRequiredLink(Link.REL_SELF);
assertThat(link).isNotNull();
assertThat(resource.getLinks()).hasSize(1);
@@ -63,8 +64,10 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
public void usesAlternateIdIfGivenExplicitly() {
PersonResource resource = assembler.createResourceWithId(person.alternateId, person);
Link selfLink = resource.getId();
assertThat(selfLink.getHref()).endsWith("/people/id");
Optional<Link> selfLink = resource.getId();
assertThat(selfLink.map(Link::getHref)) //
.hasValueSatisfying(it -> assertThat(it.endsWith("/people/id")));
}
@Test
@@ -72,8 +75,10 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
PersonResource resource = new PersonResourceAssembler(ParameterizedController.class).createResource(person, person,
"bar");
Link selfLink = resource.getId();
assertThat(selfLink.getHref()).endsWith("/people/10/bar/addresses/10");
Optional<Link> selfLink = resource.getId();
assertThat(selfLink.map(Link::getHref)) //
.hasValueSatisfying(it -> assertThat(it.endsWith("/people/id")));
}
@Test
@@ -114,8 +119,8 @@ public class IdentifiableResourceAssemblerSupportUnitTest extends TestUtils {
String alternateId;
@Override
public Long getId() {
return id;
public Optional<Long> getId() {
return Optional.ofNullable(id);
}
}