#64 - Extended support for PagedResources.
Changed Relation type to identify previous links to standardized value of prev. Added integration tests for HAL rendering of PagedResources.
This commit is contained in:
@@ -42,7 +42,7 @@ public class Link implements Serializable {
|
||||
|
||||
public static final String REL_SELF = "self";
|
||||
public static final String REL_FIRST = "first";
|
||||
public static final String REL_PREVIOUS = "previous";
|
||||
public static final String REL_PREVIOUS = "prev";
|
||||
public static final String REL_NEXT = "next";
|
||||
public static final String REL_LAST = "last";
|
||||
|
||||
@@ -101,6 +101,25 @@ public class Link implements Serializable {
|
||||
return rel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Link} pointing to the same URI but with the given relation.
|
||||
*
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public Link withRel(String rel) {
|
||||
return new Link(href, rel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Link} pointing to the same URI but with the {@code self} relation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Link withSelfRel() {
|
||||
return withRel(Link.REL_SELF);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
|
||||
@@ -87,6 +87,16 @@ public class Links implements Iterable<Link> {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Links} container contains a {@link Link} with the given rel.
|
||||
*
|
||||
* @param rel
|
||||
* @return
|
||||
*/
|
||||
public boolean hasLink(String rel) {
|
||||
return getLink(rel) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Links} instance from the given RFC5988-compatible link format.
|
||||
*
|
||||
@@ -114,6 +124,15 @@ public class Links implements Iterable<Link> {
|
||||
return new Links(links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link Links} containter is empty.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return links.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
|
||||
@@ -34,6 +34,8 @@ import org.springframework.util.Assert;
|
||||
@com.fasterxml.jackson.annotation.JsonAutoDetect(fieldVisibility = com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY)
|
||||
public class PagedResources<T> extends Resources<T> {
|
||||
|
||||
public static PagedResources<?> NO_PAGE = new PagedResources<Object>();
|
||||
|
||||
@org.codehaus.jackson.annotate.JsonProperty("page")
|
||||
@com.fasterxml.jackson.annotation.JsonProperty("page")
|
||||
private PageMetadata metadata;
|
||||
@@ -97,13 +99,37 @@ public class PagedResources<T> extends Resources<T> {
|
||||
return new PagedResources<T>(resources, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Link pointing to the next page (if set).
|
||||
*
|
||||
* @see #addPaginationLinks(Link)
|
||||
* @return
|
||||
*/
|
||||
@com.fasterxml.jackson.annotation.JsonIgnore
|
||||
@org.codehaus.jackson.annotate.JsonIgnore
|
||||
public Link getNextLink() {
|
||||
return getLink(Link.REL_NEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Link pointing to the previous page (if set).
|
||||
*
|
||||
* @see #addPaginationLinks(Link)
|
||||
* @return
|
||||
*/
|
||||
@com.fasterxml.jackson.annotation.JsonIgnore
|
||||
@org.codehaus.jackson.annotate.JsonIgnore
|
||||
public Link getPreviousLink() {
|
||||
return getLink(Link.REL_PREVIOUS);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.hateoas.ResourceSupport#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PagedResource { content: %s, metadata: %s }", getContent(), metadata);
|
||||
return String.format("PagedResource { content: %s, metadata: %s, links: %s }", getContent(), metadata, getLinks());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -173,19 +199,35 @@ public class PagedResources<T> extends Resources<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PageMetadata} from the given size, number, total elements and total pages.
|
||||
*
|
||||
* @param size
|
||||
* @param number
|
||||
* @param number zero-indexed, must be less than totalPages
|
||||
* @param totalElements
|
||||
* @param totalPages
|
||||
*/
|
||||
public PageMetadata(long size, long number, long totalElements, long totalPages) {
|
||||
|
||||
Assert.isTrue(number < totalPages,
|
||||
"The current page number cannot be greater or equal to the total number of pages!");
|
||||
|
||||
this.size = size;
|
||||
this.number = number;
|
||||
this.totalElements = totalElements;
|
||||
this.totalPages = totalPages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PageMetadata} from the given size, numer and total elements.
|
||||
*
|
||||
* @param size the size of the page
|
||||
* @param number the number of the page
|
||||
* @param totalElements the total number of elements available
|
||||
*/
|
||||
public PageMetadata(long size, long number, long totalElements) {
|
||||
this(size, number, totalElements, totalElements / size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested size of the page.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.hateoas;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.PagedResources.PageMetadata;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PagedResources}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PagedResourcesUnitTest {
|
||||
|
||||
static final PageMetadata metadata = new PagedResources.PageMetadata(10, 1, 200);
|
||||
|
||||
PagedResources<Object> resources;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
resources = new PagedResources<Object>(Collections.emptyList(), metadata);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoversNextLink() {
|
||||
|
||||
resources.add(new Link("foo", Link.REL_NEXT));
|
||||
|
||||
assertThat(resources.getNextLink(), is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoversPreviousLink() {
|
||||
|
||||
resources.add(new Link("custom", Link.REL_PREVIOUS));
|
||||
|
||||
assertThat(resources.getPreviousLink(), is(notNullValue()));
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.AbstractMarshallingIntegrationTests;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.PagedResources.PageMetadata;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
@@ -49,6 +52,10 @@ public class Jackson1HalIntegrationTest extends AbstractMarshallingIntegrationTe
|
||||
static final String ANNOTATED_EMBEDDED_RESOURCE_REFERENCE = "{\"_links\":{\"self\":{\"href\":\"localhost\"}},\"_embedded\":{\"pojo\":{\"text\":\"test1\",\"number\":1,\"_links\":{\"self\":{\"href\":\"localhost\"}}}}}";
|
||||
static final String ANNOTATED_EMBEDDED_RESOURCES_REFERENCE = "{\"_embedded\":{\"pojos\":[{\"text\":\"test1\",\"number\":1,\"_links\":{\"self\":{\"href\":\"localhost\"}}},{\"text\":\"test2\",\"number\":2,\"_links\":{\"self\":{\"href\":\"localhost\"}}}]}}";
|
||||
|
||||
static final String ANNOTATED_PAGED_RESOURCES = "{\"_links\":{\"next\":{\"href\":\"foo\"},\"prev\":{\"href\":\"bar\"}},\"_embedded\":{\"pojos\":[{\"text\":\"test1\",\"number\":1,\"_links\":{\"self\":{\"href\":\"localhost\"}}},{\"text\":\"test2\",\"number\":2,\"_links\":{\"self\":{\"href\":\"localhost\"}}}]},\"page\":{\"size\":2,\"totalElements\":4,\"totalPages\":2,\"number\":0}}";
|
||||
|
||||
static final Links PAGINATION_LINKS = new Links(new Link("foo", Link.REL_NEXT), new Link("bar", Link.REL_PREVIOUS));
|
||||
|
||||
@Before
|
||||
public void setUpModule() {
|
||||
|
||||
@@ -232,6 +239,30 @@ public class Jackson1HalIntegrationTest extends AbstractMarshallingIntegrationTe
|
||||
assertThat(result, is(setupAnnotatedResources()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializesPagedResource() throws Exception {
|
||||
assertThat(write(setupAnnotatedPagedResources()), is(ANNOTATED_PAGED_RESOURCES));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializesPagedResource() throws Exception {
|
||||
PagedResources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(
|
||||
ANNOTATED_PAGED_RESOURCES,
|
||||
mapper.getTypeFactory().constructParametricType(PagedResources.class,
|
||||
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
|
||||
|
||||
assertThat(result, is(setupAnnotatedPagedResources()));
|
||||
}
|
||||
|
||||
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedPagedResources() {
|
||||
|
||||
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<Resource<SimpleAnnotatedPojo>>();
|
||||
content.add(new Resource<SimpleAnnotatedPojo>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
|
||||
content.add(new Resource<SimpleAnnotatedPojo>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
|
||||
|
||||
return new PagedResources<Resource<SimpleAnnotatedPojo>>(content, new PageMetadata(2, 0, 4), PAGINATION_LINKS);
|
||||
}
|
||||
|
||||
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedResources() {
|
||||
|
||||
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<Resource<SimpleAnnotatedPojo>>();
|
||||
|
||||
@@ -25,6 +25,9 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.AbstractJackson2MarshallingIntegrationTests;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.PagedResources.PageMetadata;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
@@ -49,6 +52,10 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
|
||||
static final String ANNOTATED_EMBEDDED_RESOURCE_REFERENCE = "{\"_links\":{\"self\":{\"href\":\"localhost\"}},\"_embedded\":{\"pojo\":{\"text\":\"test1\",\"number\":1,\"_links\":{\"self\":{\"href\":\"localhost\"}}}}}";
|
||||
static final String ANNOTATED_EMBEDDED_RESOURCES_REFERENCE = "{\"_links\":{},\"_embedded\":{\"pojos\":[{\"text\":\"test1\",\"number\":1,\"_links\":{\"self\":{\"href\":\"localhost\"}}},{\"text\":\"test2\",\"number\":2,\"_links\":{\"self\":{\"href\":\"localhost\"}}}]}}";
|
||||
|
||||
static final String ANNOTATED_PAGED_RESOURCES = "{\"_links\":{\"next\":{\"href\":\"foo\"},\"prev\":{\"href\":\"bar\"}},\"_embedded\":{\"pojos\":[{\"text\":\"test1\",\"number\":1,\"_links\":{\"self\":{\"href\":\"localhost\"}}},{\"text\":\"test2\",\"number\":2,\"_links\":{\"self\":{\"href\":\"localhost\"}}}]},\"page\":{\"size\":2,\"totalElements\":4,\"totalPages\":2,\"number\":0}}";
|
||||
|
||||
static final Links PAGINATION_LINKS = new Links(new Link("foo", Link.REL_NEXT), new Link("bar", Link.REL_PREVIOUS));
|
||||
|
||||
@Before
|
||||
public void setUpModule() {
|
||||
|
||||
@@ -238,6 +245,30 @@ public class Jackson2HalIntegrationTest extends AbstractJackson2MarshallingInteg
|
||||
assertThat(result, is(setupAnnotatedResources()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializesPagedResource() throws Exception {
|
||||
assertThat(write(setupAnnotatedPagedResources()), is(ANNOTATED_PAGED_RESOURCES));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserializesPagedResource() throws Exception {
|
||||
PagedResources<Resource<SimpleAnnotatedPojo>> result = mapper.readValue(
|
||||
ANNOTATED_PAGED_RESOURCES,
|
||||
mapper.getTypeFactory().constructParametricType(PagedResources.class,
|
||||
mapper.getTypeFactory().constructParametricType(Resource.class, SimpleAnnotatedPojo.class)));
|
||||
|
||||
assertThat(result, is(setupAnnotatedPagedResources()));
|
||||
}
|
||||
|
||||
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedPagedResources() {
|
||||
|
||||
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<Resource<SimpleAnnotatedPojo>>();
|
||||
content.add(new Resource<SimpleAnnotatedPojo>(new SimpleAnnotatedPojo("test1", 1), new Link("localhost")));
|
||||
content.add(new Resource<SimpleAnnotatedPojo>(new SimpleAnnotatedPojo("test2", 2), new Link("localhost")));
|
||||
|
||||
return new PagedResources<Resource<SimpleAnnotatedPojo>>(content, new PageMetadata(2, 0, 4), PAGINATION_LINKS);
|
||||
}
|
||||
|
||||
private static Resources<Resource<SimpleAnnotatedPojo>> setupAnnotatedResources() {
|
||||
|
||||
List<Resource<SimpleAnnotatedPojo>> content = new ArrayList<Resource<SimpleAnnotatedPojo>>();
|
||||
|
||||
Reference in New Issue
Block a user