Java源码示例:de.otto.edison.hal.HalRepresentation
示例1
/**
* Returns an application/hal+json representation of the container-resource containing all staterepositories that
* are not {@link EdisonStateRepositoryUiProperties#getExcluded() excluded} from the state-repository UI.
*
* @param request current HttpServletRequest
* @return HalRepresentation of the collection of state repositories
*/
@GetMapping(
path = "${edison.application.management.base-path:internal}/staterepositories",
produces = {"application/hal+json", "application/json"}
)
@ResponseBody
public HalRepresentation getStateRepositories(final HttpServletRequest request) {
final String selfHref = request.getRequestURL().toString();
final List<Link> itemLinks = itemLinks(selfHref);
return new HalRepresentation(
linkingTo()
.self(selfHref)
.array(itemLinks)
.build()
);
}
示例2
/**
* Entry point for the products REST API.
*
* @param request current request
* @return application/hal+json document containing links to the API.
*/
@RequestMapping(
path = "/api",
method = RequestMethod.GET,
produces = {"application/hal+json", "application/json"}
)
public HalRepresentation getHomeDocument(final HttpServletRequest request) {
final String homeUrl = request.getRequestURL().toString();
return new HalRepresentation(
linkingTo()
.self(homeUrl)
.single(linkBuilder("search", "/api/products{?q,embedded}")
.withTitle("Search Products")
.withType("application/hal+json")
.build())
.build()
);
}
示例3
/**
* @return application/hal+json document containing links to the API.
*/
@RequestMapping(
path = "/api/products/{productId}",
method = RequestMethod.GET,
produces = {"application/hal+json", "application/json"}
)
public HalRepresentation getProduct(@PathVariable final String productId,
final HttpServletResponse response) throws IOException {
Optional<Product> product = productSearch.findBy(productId);
if (product.isPresent()) {
return new ProductHalJson(product.get());
} else {
response.sendError(SC_NOT_FOUND, "Product " + productId + " not found");
return null;
}
}
示例4
@Test
public void shouldNotPageBeforeFirstPage() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example/foo"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/1\"}," +
"{\"href\":\"/example/foo/2\"}]" +
"}" +
"}");
// when
final Optional<HalRepresentation> optionalPage = traverson(mock)
.startWith("http://example.com/example/foo")
.follow("prev")
.getResource();
// then
assertThat(optionalPage.isPresent(), is(false));
}
示例5
@Test
@SuppressWarnings("unchecked")
public void shouldCreateTraversonFromContextUrlAndHalRepresentationWithoutSelfLinkButWithRelativeLinks() throws IOException {
// given
final HalRepresentation existingRepresentation = new HalRepresentation(
linkingTo().array(link("search", "/example/foo")).build()
);
// when
Traverson traverson = traverson(mock(LinkResolver.class))
.startWith(new URL("http://example.com"), existingRepresentation);
// then
assertThat(traverson.getCurrentContextUrl(), is(new URL("http://example.com")));
// and when
Optional<HalRepresentation> resource = traverson.getResource();
// then
assertThat(resource.isPresent(), is(true));
assertThat(traverson.getCurrentContextUrl(), is(new URL("http://example.com")));
}
示例6
@Test
@SuppressWarnings("unchecked")
public void shouldCreateTraversonFromHalRepresentationWithoutSelfLinkButWithAbsoluteLinks() throws IOException {
// given
final HalRepresentation existingRepresentation = new HalRepresentation(
linkingTo().array(link("search", "http://example.com/example/")).build()
);
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("search", "http://example.com/example/"))).thenReturn(
"{\"_links\":{\"foo\":{\"href\":\"http://example.com/example/foo\"}}}");
// when
final Traverson traverson = traverson(mock)
.startWith(existingRepresentation)
.follow("search");
// then
assertThat(traverson.getCurrentContextUrl(), is(nullValue()));
// and when
Optional<HalRepresentation> resource = traverson.getResource();
// then
assertThat(resource.isPresent(), is(true));
assertThat(traverson.getCurrentContextUrl(), is(new URL("http://example.com/example/")));
}
示例7
@Test
public void shouldFollowLinkUsingCustomObjectMapper() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(self("http://example.com/example"))).thenReturn(
"{\"_links\":{\"foo\":[{\"href\":\"http://example.com/example/foo\"}]}}");
when(mock.apply(link("foo", "http://example.com/example/foo"))).thenReturn(
"{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}");
// when
final HalRepresentation hal = traverson(mock, new ObjectMapper())
.startWith("http://example.com/example")
.follow("foo")
.getResource()
.get();
final HalRepresentation expectedHalt = traverson(mock)
.startWith("http://example.com/example")
.follow("foo")
.getResource()
.get();
// then
assertThat(hal, is(expectedHalt));
}
示例8
@Test
public void shouldFollowLinkStartingWithHalRepresentationHavingAbsoluteLinks() throws IOException {
// given
final HalRepresentation existingRepresentation = new HalRepresentation(
linkingTo().single(link("search", "http://example.com/example/foo")).build()
);
// and
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("search", "http://example.com/example/foo"))).thenReturn(
"{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}");
// when
final Optional<HalRepresentation> hal = traverson(mock)
.startWith(existingRepresentation)
.follow("search")
.getResource();
// then
final Optional<Link> self = hal.get().getLinks().getLinkBy("self");
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例9
@Test
public void shouldFollowLinkStartingWithHalRepresentationAndContextUrl() throws IOException {
// given
final HalRepresentation existingRepresentation = new HalRepresentation(
linkingTo().single(link("search", "/example/foo")).build());
// and
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("search", "http://example.com/example/foo"))).thenReturn(
"{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}");
// when
final Optional<HalRepresentation> hal = traverson(mock)
.startWith(new URL("http://example.com"), existingRepresentation)
.follow("search")
.getResource();
// then
final Optional<Link> self = hal.get().getLinks().getLinkBy("self");
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例10
@Test
public void shouldFollowTemplatedLink() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self","http://example.com/example"))).thenReturn("{\"_links\":{\"foo\":{\"templated\":true,\"href\":\"/example/foo{?test}\"}}}");
when(mock.apply(link("foo", "http://example.com/example/foo?test=bar"))).thenReturn("{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.follow("foo", withVars("test", "bar"))
.getResource()
.get();
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例11
@Test
public void shouldFollowMultipleTemplatedLinks() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example"))).thenReturn("{\"_links\":{\"foo\":{\"templated\":true,\"href\":\"/example/foo{?param1}\"}}}");
when(mock.apply(link("foo", "http://example.com/example/foo?param1=value1"))).thenReturn("{\"_links\":{\"bar\":{\"templated\":true,\"href\":\"/example/bar{?param2}\"}}}");
when(mock.apply(link("bar", "http://example.com/example/bar?param2=value2"))).thenReturn("{\"_links\":{\"self\":{\"href\":\"http://example.com/example/bar\"}}}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.follow(
hops("foo", "bar"),
withVars("param1", "value1", "param2", "value2"))
.getResource()
.get();
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/bar"));
}
示例12
@Test
public void shouldFollowLinkWithEmbeddedObjects() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(any(Link.class))).thenReturn(
"{" +
"\"_embedded\":{\"foo\":[{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}]}" +
"}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.follow("foo")
.getResource()
.get();
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例13
@Test
public void shouldFollowLinkIgnoringEmbeddedObjects() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(any(Link.class))).thenReturn(
"{" +
"\"_links\":{\"foo\":[{\"href\":\"http://example.com/example/foo\"}]}," +
"\"_embedded\":{\"foo\":[{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}]}" +
"}",
"{" +
"\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}" +
"}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.followLink("foo")
.getResource()
.get();
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例14
@Test
public void shouldFollowEmbeddedIfLinkIsMissing() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(any(Link.class))).thenReturn(
"{" +
"\"_embedded\":{\"foo\":[{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}]}" +
"}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.followLink("foo")
.getResource()
.get();
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例15
@Test
public void shouldProvideCustomNestedObjectsAsHalRepresentation() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(any(Link.class))).thenReturn(
"{" +
"\"bar\":[" +
" {\"_links\":{\"self\":{\"href\":\"http://example.com/example/1\"}}}," +
" {\"_links\":{\"self\":{\"href\":\"http://example.com/example/2\"}}}" +
"]" +
"}");
// when
final List<HalRepresentation> hal = traverson(mock)
.startWith("http://example.com/example")
.getResourceAs(NestedHalRepresentation.class)
.get()
.bar;
// then
final Optional<Link> first = hal.get(0).getLinks().getLinkBy("self");
assertThat(first.isPresent(), is(true));
assertThat(first.get().getHref(), is("http://example.com/example/1"));
final Optional<Link> second = hal.get(1).getLinks().getLinkBy("self");
assertThat(second.isPresent(), is(true));
assertThat(second.get().getHref(), is("http://example.com/example/2"));
}
示例16
@Test
public void shouldFollowLinkWithEmbeddedObjectAndSelectResource() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(any(Link.class))).thenReturn(
"{" +
" \"_embedded\":{\"bar\":" +
" {\"foo\":{\"_links\":{\"self\":{\"href\":\"http://example.com/example/foo\"}}}}" +
" }" +
"}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.follow("bar")
.getResourceAs(NestedHalRepresentation.class)
.get()
.foo;
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/foo"));
}
示例17
/**
* Returns an application/hal+json representation of the event journal of a single event-sourced entity.
*
* @param repositoryName the name of the {@link Journal}
* @param entityId the id of the requested entity
* @param uriComponentsBuilder builder used to create hrefs
*
* @return HalRepresentation the representation of the journal
*/
@GetMapping(
path = "${edison.application.management.base-path:internal}/journals/{repositoryName}/{entityId}",
produces = {"application/hal+json", "application/json"}
)
@ResponseBody
public HalRepresentation getEntityJournalJson(final @PathVariable String repositoryName,
final @PathVariable String entityId,
final UriComponentsBuilder uriComponentsBuilder) {
final String baseUri = uriComponentsBuilder.pathSegment(managementBasePath).toUriString();
final String selfUri = baseUri + "/journals/" + repositoryName + "/" + entityId;
if (journals.hasJournal(repositoryName)) {
final List<MessageStoreEntryRepresentation> messages =
journals.getJournal(repositoryName)
.map(journal -> journal.getJournalFor(entityId)
.map(MessageStoreEntryRepresentation::new)
.collect(toList()))
.orElse(emptyList());
final Links.Builder links = linkingTo()
.self(selfUri);
if (stateRepositories.containsKey(repositoryName)) {
links
.single(
link("working-copy", baseUri + "/staterepositories/" + repositoryName + "/" + entityId))
.single(
collection(baseUri + "/staterepositories/" + repositoryName + "{?page,pageSize}"));
}
return new JournalHalRepresentation(
links.build(),
messages);
} else {
throw new ResponseStatusException(NOT_FOUND, "No such Journal " + repositoryName);
}
}
示例18
/**
* Returns an application/hal+json representation of a single event-sourced entity stored in the
* {@link StateRepository} with the specified {@code repositoryName}.
*
* <p>If the state repository has a {@link Journal}, the returned
* entity representation will contain a link to the messages that where leading to the current state of the
* entity.</p>
*
* @param repositoryName the name of the {@code StateRepository}
* @param entityId the id of the requested entity
* @param uriComponentsBuilder builder used to create hrefs
*
* @return HalRepresentation the representation of the entity
*/
@GetMapping(
path = "${edison.application.management.base-path:internal}/staterepositories/{repositoryName}/{entityId}",
produces = {"application/hal+json", "application/json"}
)
@ResponseBody
public HalRepresentation getEntityJson(final @PathVariable String repositoryName,
final @PathVariable String entityId,
final UriComponentsBuilder uriComponentsBuilder) {
final String baseUri = uriComponentsBuilder.pathSegment(managementBasePath).toUriString();
if (stateRepositories.containsKey(repositoryName)) {
final StateRepository<?> stateRepository = stateRepositories.get(repositoryName);
final Links.Builder links = linkingTo()
.self(
baseUri + "/" + repositoryName + "/staterepositories/" + entityId)
.single(
collection(baseUri + "/staterepositories/" + repositoryName + "{?page,pageSize}"));
if (journals.hasJournal(repositoryName)) {
links.single(
link("working-copy-of", baseUri + "/journals/" + repositoryName + "/" + entityId));
}
return new EntityHalRepresentation(
links.build(),
stateRepository.get(entityId));
} else {
throw new ResponseStatusException(NOT_FOUND, "No such StateRepository " + repositoryName);
}
}
示例19
/**
* @return application/hal+json document containing links to the API.
*/
@RequestMapping(
path = "/api/products",
method = RequestMethod.GET,
produces = {"application/hal+json", "application/json"}
)
public HalRepresentation getProducts(@RequestParam(defaultValue = "false") final boolean embedded,
@RequestParam(required = false) final String q) {
return new ProductsHalJson(productSearch.searchFor(ofNullable(q)), embedded);
}
示例20
@Test
public void shouldPageOverLinksUsingNext() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example/foo"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/1\"}," +
"{\"href\":\"/example/foo/2\"}]," +
"\"next\":" +
"{\"href\":\"/example/foo?page=2\"}" +
"}" +
"}");
when(mock.apply(link("next", "http://example.com/example/foo?page=2"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/3\"}," +
"{\"href\":\"/example/foo/4\"}]," +
"\"prev\":" +
"{\"href\":\"/example/foo\"}" +
"}" +
"}");
// when
Optional<HalRepresentation> optionalPage = traverson(mock)
.startWith("http://example.com/example/foo")
.follow("next")
.getResource();
// then
assertThat(optionalPage.isPresent(), is(true));
}
示例21
@Test
public void shouldNotPageAfterLastPage() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example/foo"))).thenReturn("{}");
// when we getResource the next page
final Optional<HalRepresentation> optionalPage = traverson(mock)
.startWith("http://example.com/example/foo")
.follow("next")
.getResource();
assertThat(optionalPage.isPresent(), is(false));
}
示例22
@Test
public void shouldPageOverLinksUsingPrev() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example/foo?page=2"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/3\"}," +
"{\"href\":\"/example/foo/4\"}]," +
"\"prev\":" +
"{\"href\":\"/example/foo\"}" +
"}" +
"}");
when(mock.apply(link("prev", "http://example.com/example/foo"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/1\"}," +
"{\"href\":\"/example/foo/2\"}]," +
"\"next\":" +
"{\"href\":\"/example/foo?page=2\"}" +
"}" +
"}");
// when
final Optional<HalRepresentation> optionalPage = traverson(mock)
.startWith("http://example.com/example/foo?page=2")
.follow("prev")
.getResource();
// then
assertThat(optionalPage.isPresent(), is(true));
}
示例23
@Test(expected = IllegalArgumentException.class)
@SuppressWarnings("unchecked")
public void shouldNotCreateTraversonFromHalRepresentationWithoutSelfLinkButWithRelativeLinks() {
// given
final HalRepresentation existingRepresentation = new HalRepresentation(
linkingTo().single(link("search", "/example/foo")).build()
);
// when
traverson(mock(LinkResolver.class))
.startWith(existingRepresentation);
}
示例24
@Test
public void shouldFollowTemplatedLinksWithPredicates() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example")))
.thenReturn("{\"_links\":{\"foo\":[" +
"{\"templated\":true,\"type\":\"text/plain\",\"href\":\"/example/foo1{?param1}\"}," +
"{\"templated\":true,\"type\":\"text/html\",\"href\":\"/example/foo2{?param1}\"}]}}");
when(mock.apply(linkBuilder("foo", "http://example.com/example/foo2?param1=value1").withType("text/html").build()))
.thenReturn("{\"_links\":{\"bar\":{\"templated\":true,\"href\":\"/example/bar{?param2}\"}}}");
when(mock.apply(link("bar", "http://example.com/example/bar?param2=value2")))
.thenReturn("{\"_links\":{\"self\":{\"href\":\"http://example.com/example/bar\"}}}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.follow(
hops("foo", "bar"),
optionallyHavingType("text/html"),
withVars("param1", "value1", "param2", "value2"))
.getResource()
.get();
// then
final Optional<Link> self = hal.getLinks().getLinkBy("self");
assertThat(self.isPresent(), is(true));
assertThat(self.get().getHref(), is("http://example.com/example/bar"));
}
示例25
@Test
public void shouldGetSingleEmbeddedHalRepresentationAsSubtype() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(any(Link.class))).thenReturn(
"{\"_embedded\":{\"foo\":[{\"someProperty\":\"bar\"}]}}");
// when
final HalRepresentation hal = traverson(mock)
.startWith("http://example.com/example")
.getResourceAs(HalRepresentation.class, withEmbedded("foo", ExtendedHalRepresentation.class))
.get();
// then
assertThat(hal.getEmbedded().getItemsBy("foo", ExtendedHalRepresentation.class).get(0).someProperty, is("bar"));
}
示例26
/**
* Returns an application/hal+json representation of a {@link StateRepository}, containing a pageable collection
* resource with links to the event-sourced entities stored in the repository.
*
* @param repositoryName the name of the StateRepository
* @param page the zero-based page number
* @param pageSize the number of entities to return
* @param uriComponentsBuilder builder used to create hrefs
*
* @return HalRepresentation of the paged collection resource
*/
@GetMapping(
path = "${edison.application.management.base-path:internal}/staterepositories/{repositoryName}",
produces = {"application/hal+json", "application/json"}
)
@ResponseBody
public HalRepresentation getStateRepository(final @PathVariable String repositoryName,
final @RequestParam(defaultValue = "0") int page,
final @RequestParam(defaultValue = "100") int pageSize,
final UriComponentsBuilder uriComponentsBuilder) {
if (stateRepositories.containsKey(repositoryName)) {
final UriComponentsBuilder baseUriBuilder = uriComponentsBuilder
.pathSegment(managementBasePath)
.path("/staterepositories");
final UriTemplate repositoriesUri = fromTemplate(baseUriBuilder.toUriString());
final UriTemplate repositoryUri = fromTemplate(baseUriBuilder.toUriString() + "/" + repositoryName + "{?page,pageSize}");
final UriTemplate entityUri = fromTemplate(baseUriBuilder.toUriString() + "/" + repositoryName + "/{entityId}");
final StateRepository<?> stateRepository = stateRepositories
.get(repositoryName);
final Set<String> allEntityIds = stateRepository.keySet();
final List<String> entityPageIds = allEntityIds
.stream()
.skip(page * pageSize)
.limit(pageSize)
.collect(toList());
final Links pagingLinks = pageSize > 0
? zeroBasedNumberedPaging(page, pageSize, (int)stateRepository.size()).links(repositoryUri, allOf(PagingRel.class))
: emptyLinks();
final List<Link> itemLinks = entityItemLinks(entityUri, entityPageIds);
return new HalRepresentation(
linkingTo()
.with(pagingLinks)
.single(collection(repositoriesUri.expand()))
.array(itemLinks).build()
);
} else {
throw new ResponseStatusException(NOT_FOUND, "No such StateRepository " + repositoryName);
}
}
示例27
@Test
public void shouldPageOverLinksUsingFirstAndLast() throws IOException {
// given
@SuppressWarnings("unchecked")
final LinkResolver mock = mock(LinkResolver.class);
when(mock.apply(link("self", "http://example.com/example/foo"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/1\"}," +
"{\"href\":\"/example/foo/2\"}]," +
"\"last\":" +
"{\"href\":\"/example/foo?page=2\"}" +
"}" +
"}");
when(mock.apply(link("first", "http://example.com/example/foo"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/1\"}," +
"{\"href\":\"/example/foo/2\"}]," +
"\"last\":" +
"{\"href\":\"/example/foo?page=2\"}" +
"}" +
"}");
when(mock.apply(link("last", "http://example.com/example/foo?page=2"))).thenReturn(
"{" +
"\"_links\":{" +
"\"foo\":[" +
"{\"href\":\"/example/foo/3\"}," +
"{\"href\":\"/example/foo/4\"}]," +
"\"first\":" +
"{\"href\":\"/example/foo\"}" +
"}" +
"}");
final Traverson traverson = traverson(mock);
// when we getResource the next page
Optional<HalRepresentation> optionalPage = traverson
.startWith("http://example.com/example/foo")
.follow("last")
.getResource();
assertThat(optionalPage.isPresent(), is(true));
List<String> hrefs = optionalPage.get().getLinks().getLinksBy("foo")
.stream()
.map(Link::getHref)
.collect(toList());
// then
assertThat(hrefs, contains("/example/foo/3","/example/foo/4"));
// when we return to previous page
optionalPage = traverson.follow("first").getResource();
hrefs = optionalPage.get().getLinks().getLinksBy("foo")
.stream()
.map(Link::getHref)
.collect(toList());
// then
assertThat(hrefs, contains("/example/foo/1","/example/foo/2"));
}