I have a data access layer made with Spring-Data. I'm now creating a web application on top of it. This one controller method should return a Spring-Data Page formatted as JSON.
Such a Page is a List with additional Paging info like total amount of records and so forth.
Is that possible and if yes how?
And directly related to that can I define the mapping of property names? Eg. meaning I would need define how the paging info properties are named in JSON (differently than in page). Is this possible and how?
There's support for a scenario like this upcoming in Spring HATEOAS and Spring Data Commons. Spring HATEOAS comes with a PageMetadata
object that essentially contains the same data as a Page
but in a less enforcing manner, so that it can be more easily marshaled and unmarshaled.
Another aspect of the reason we implement this in combination with Spring HATEOAS and Spring Data commons is that there's little value in simply marshaling the page, it's content and the metadata but also want to generate the links to maybe existing next or previous pages, so that the client doesn't have to construct URIs to traverse these pages itself.
Assume a domain class Person
:
class Person {
Long id;
String firstname, lastname;
}
as well as it's corresponding repository:
interface PersonRepository extends PagingAndSortingRepository<Person, Long> { }
You can now expose a Spring MVC controller as follows:
@Controller
class PersonController {
@Autowired PersonRepository repository;
@RequestMapping(value = "/persons", method = RequestMethod.GET)
HttpEntity<PagedResources<Person>> persons(Pageable pageable,
PagedResourcesAssembler assembler) {
Page<Person> persons = repository.findAll(pageable);
return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
}
}
There's probably quite a bit to explain here. Let's take it step by step:
@Enable(Jpa|Mongo|Neo4j|Gemfire)Repositories
or the XML equivalents). The controller method is mapped to /persons
, which means it will accept all GET
requests to that method.PagedResources
- a type from Spring HATEOAS that represents some content enriched with Links
plus a PageMetadata
. When the method is invoked, Spring MVC will have to create instances for Pageable
and PagedResourcesAssembler
. To get this working you need to enable the Spring Data web support either through the @EnableSpringDataWebSupport
annotation about to be introduced in the upcoming milestone of Spring Data Commons or via standalone bean definitions (documented here).
The Pageable
will be populated with information from the request. The default configuration will turn ?page=0&size=10
into a Pageable
requesting the first page by a page size of 10.
The PageableResourcesAssembler
allows you to easily turn a Page
into a PagedResources
instances. It will not only add the page metadata to the response but also add the appropriate links to the representation based on what page you access and how your Pageable
resolution is configured.
A sample JavaConfig configuration to enable this for JPA would look like this:
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
@EnableJpaRepositories
class ApplicationConfig {
// declare infrastructure components like EntityManagerFactory etc. here
}
Assume we have 30 Persons
in the database. You can now trigger a request GET http://localhost:8080/persons
and you'll see something similar to this:
{ "links" : [
{ "rel" : "next", "href" : "http://localhost:8080/persons?page=1&size=20 }
],
"content" : [
… // 20 Person instances rendered here
],
"pageMetadata" : {
"size" : 20,
"totalElements" : 30,
"totalPages" : 2,
"number" : 0
}
}
Note that the assembler produced the correct URI and also picks up the default configuration present to resolve the parameters into a Pageable
for an upcoming request. This means, if you change that configuration, the links will automatically adhere to the change. By default the assembler points to the controller method it was invoked in but that can be customized by handing in a custom Link
to be used as base to build the pagination links to overloads of the PagedResourcesAssembler.toResource(…)
method.
The PagedResourcesAssembler
bits will be available in the upcoming milestone release of the Spring Data Babbage release train. It's already available in the current snapshots. You can see a working example of this in my Spring RESTBucks sample application. Simply clone it, run mvn jetty:run
and curl http://localhost:8080/pages
.