Spring Boot HATEOAS Output Fails - spring

The output of my entities in a Sprint Boot REST HATEOAS service does not work. The service returns an empty string for each entity. There are no error messages. I have tried Spring Boot 1.5.4 and 2.0.0.RC1.
Full source code is on GitHub: https://github.com/murygin/hateoas-people-service
Application
#SpringBootApplication
#Configuration
#EnableHypermediaSupport(type={EnableHypermediaSupport.HypermediaType.HAL})
public class Application {
public static void main(String args[]) {
SpringApplication.run(Application.class);
}
}
PersonController
#RestController
#RequestMapping(value = "/persons", produces = "application/hal+json")
public class PersonController {
#GetMapping
public ResponseEntity<Resources<PersonResource>> all() {
final List<PersonResource> collection =
getPersonList().stream().map(PersonResource::new).collect(Collectors.toList());
final Resources<PersonResource> resources = new Resources<>(collection);
final String uriString = ServletUriComponentsBuilder.fromCurrentRequest().build().toUriString();
resources.add(new Link(uriString, "self"));
return ResponseEntity.ok(resources);
}
#GetMapping("/{id}")
public ResponseEntity<PersonResource> get(#PathVariable final long id) {
Person p = new Person((long)1,"Donald","Duck");
return ResponseEntity.ok(new PersonResource(p));
}
private List<Person> getPersonList() {
List<Person> personList = new LinkedList<>();
personList.add(new Person((long)1,"Donald","Duck"));
personList.add(new Person((long)2,"Dagobert","Duck"));
personList.add(new Person((long)3,"Daniel","Duesentrieb"));
return personList;
}
}
PersonResource
public class PersonResource extends ResourceSupport {
private final Person person;
public PersonResource(final Person person) {
this.person = person;
final long id = person.getId();
add(linkTo(PersonController.class).withRel("people"));
add(linkTo(methodOn(PersonController.class).get(id)).withSelfRel());
}
}
Person
public class Person {
private Long id;
private String firstName;
private String secondName;
public Person() {
}
public Person(Long id, String firstName, String secondName) {
this.id = id;
this.firstName = firstName;
this.secondName = secondName;
}
// getter and setter...
}
Output of http://localhost:8080/persons
{
_embedded: {
personResourceList: [{
_links: {
people: {
href: "http://localhost:8080/persons"
},
self: {
href: "http://localhost:8080/persons/1"
}
}
},
{
_links: {
people: {
href: "http://localhost:8080/persons"
},
self: {
href: "http://localhost:8080/persons/2"
}
}
},
{
_links: {
people: {
href: "http://localhost:8080/persons"
},
self: {
href: "http://localhost:8080/persons/3"
}
}
}
]
},
_links: {
self: {
href: "http://localhost:8080/persons"
}
}
}
Output of http://localhost:8080/persons/1
{
_links: {
people: {
href: "http://localhost:8080/persons"
},
self: {
href: "http://localhost:8080/persons/1"
}
}
}

Add a getter for person in PersonResource:
public class PersonResource extends ResourceSupport {
private final Person person;
public PersonResource(final Person person) {
this.person = person;
final long id = person.getId();
add(linkTo(PersonController.class).withRel("people"));
add(linkTo(methodOn(PersonController.class).get(id)).withSelfRel());
}
public Person getPerson() {
return person;
}
}
With the getter, Spring gets the person wrapped in your PersonResource and serializes it:
GET http://localhost:8080/persons/1
{
"person" : {
"id" : 1,
"firstName" : "Donald",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
}
GET http://localhost:8080/persons
{
"_embedded" : {
"personResources" : [ {
"person" : {
"id" : 1,
"firstName" : "Donald",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
}, {
"person" : {
"id" : 2,
"firstName" : "Dagobert",
"secondName" : "Duck"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/2"
}
}
}, {
"person" : {
"id" : 3,
"firstName" : "Daniel",
"secondName" : "Duesentrieb"
},
"_links" : {
"people" : {
"href" : "http://localhost:8080/persons"
},
"self" : {
"href" : "http://localhost:8080/persons/3"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons"
}
}
}
Note: I'm a lazy bum, I added spring-boot-starter-data-rest to the pom.xml dependencies to pretty print the result, so your actual result may vary a bit.

I suggest you a pretty less invasive approach for your case with the use of Resource instead of the extending of ResourceSupport. Your code would look like this:
#RestController
#RequestMapping(value = "/persons", produces = "application/hal+json")
public class PersonController {
#GetMapping
public ResponseEntity<List<Resource<Person>>> all() {
final List<Resource<Person>> collection =
getPersonList().stream()
.map(p -> new Resource<>(p, this.getLinks(p.getId())))
.collect(Collectors.toList());
return ResponseEntity.ok(collection);
}
#GetMapping("/{id}")
public ResponseEntity<Resource<Person>> get(#PathVariable final long id) {
Person p = new Person(id,"Donald","Duck");
Resource<Person> resource = new Resource<>(p, this.getLinks(id));
return ResponseEntity.ok(resource);
}
private List<Person> getPersonList() {
List<Person> personList = new LinkedList<>();
personList.add(new Person((long)1,"Donald","Duck"));
personList.add(new Person((long)2,"Dagobert","Duck"));
personList.add(new Person((long)3,"Daniel","Duesentrieb"));
return personList;
}
private List<Link> getLinks(long id) {
return Arrays.asList(
linkTo(PersonController.class).withRel("people"),
linkTo(methodOn(getClass()).get(id)).withSelfRel());
}
}
With more clear outputs:
GET http://localhost:8080/persons/1
{
"id": 1,
"firstName": "Donald",
"secondName": "Duck",
"_links": {
"people": {"href": "http://localhost:8080/persons"},
"self": {"href": "http://localhost:8080/persons/1"}
}
}
GET http://localhost:8080/persons
[
{
"id": 1,
"firstName": "Donald",
"secondName": "Duck",
"_links": {
"people": {"href": "http://localhost:8080/persons"},
"self": {"href": "http://localhost:8080/persons/1"}
}
},
{
"id": 2,
"firstName": "Dagobert",
"secondName": "Duck",
"_links": {
"people": {"href": "http://localhost:8080/persons"},
"self": {"href": "http://localhost:8080/persons/2"}
}
},
{
"id": 3,
"firstName": "Daniel",
"secondName": "Duesentrieb",
"_links": {
"people": {"href": "http://localhost:8080/persons"},
"self": {"href": "http://localhost:8080/persons/3"}
}
}
]
Just another point of view, hope this helps.

Related

Remove association links for content on collection resource for Spring Data REST

How configure Spring Data REST to remove entity association links (left only "self") on Collection resource response of Repository interface endpoints, without set exported=false on #ResResource annotation (need keep exported the endpoints)
We has entities where the _links part has the bigest size on the response:
On Item resource _ links are useful to navigate throught the associations.
But on Collection Resources , mainly on large collections, this information is not important and makes the response unnecesary biger .
We need change this response:
{
"_embedded" : {
"persons" : [ {
"id" : "bat_3191",
"name" : "B",
"_links" : { // 80% of response size !!
"self" : {
"href" : "http://localhost:8080/api/persons/bat_3191"
},
"orders" : {
"href" : "http://localhost:8080/api/persons/bat_3191/order"
},
"payments" : {
"href" : "http://localhost:8080/api/persons/bat_3191/payments"
},
"childrens" : {
"href" : "http://localhost:8080/api/persons/bat_3191/childrens"
},
"invoices" : {
"href" : "http://localhost:8080/api/persons/bat_3191/invoices"
},
"brands" : {
"href" : "http://localhost:8080/api/persons/bat_3191/brands"
},
}
},
{ person [2] }
...
{ person [N] }
]
},
"_links" : {
[page links]
}
To a only "self" on _links part:
{
"_embedded" : {
"persons" : [ {
"id" : "bat_3191",
"name" : "B",
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/persons/bat_3191"
}
}
}, {
"id" : "bat_2340",
"name" : "B",
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/persons/bat_2340"
}
}
If I wanted to control the hateos links in springboot I used a resource assembler. As an example:
#Autowired
private EmployeeAddressResourceAssembler assembler;
#GetMapping(value="/{empId}", produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<EmployeeAddressResource> getEmployeeAddress(#PathVariable Integer empId) {
EmployeeAddressItem employeeAddressItem = restTemplate.getForObject(
serviceUrl + "/employee/address/{empId}",
EmployeeAddressItem.class, empId);
return ResponseEntity.ok( assembler.toResource(employeeAddressItem) );
}
And then I used the resource assembler.
#Component
public class EmployeeAddressResourceAssembler
extends ResourceAssemblerSupport<EmployeeAddressItem, EmployeeAddressResource> {
public EmployeeAddressResourceAssembler() {
super(EmployeeAddressController.class, EmployeeAddressResource.class);
}
#Override
public EmployeeAddressResource toResource(EmployeeAddressItem item) {
// createResource(employeeAddressItem);
EmployeeAddressResource resource = createResourceWithId(item.getEmpId(), item);
resource.fromEmployeeAddressItem(item);
// … do further mapping
resource.add(linkTo(methodOn(EmployeeAddressController.class).deleteEmployeeAddress(item.getEmpId())).withRel("delete"));
return resource;
}
}
and the ResourceAssembler uses a Resource
public class EmployeeAddressResource extends ResourceSupport {
private Integer empId;
private String address1;
private String address2;
private String address3;
private String address4;
private String state;
private String country;
public void fromEmployeeAddressItem(EmployeeAddressItem item) {
this.empId = item.getEmpId();
this.address1 = item.getAddress1();
this.address2 = item.getAddress2();
this.address3 = item.getAddress3();
this.address4 = item.getAddress4();
this.state = item.getState();
this.country = item.getCountry();
}
All this at RestPracticeWithHateos

How to consume _embedded resources with Spring HATEOAS

I am trying to consume the following REST HAL response from a 3rd party service:
{
"id": 51780,
"name": "Lambeth",
"description": "",
"address_id": 54225,
"website": "",
"numeric_widget_id": 3602008,
"currency_code": "GBP",
"timezone": "Europe/London",
"country_code": "gb",
"live": true,
"_embedded": {
"settings": {
"has_services": true,
"has_classes": true,
"payment_tax": 0,
"currency": "GBP",
"requires_login": false,
"has_wallets": false,
"ask_address": true,
"_links": {
"self": {
"href": "https://myhost.com/api/v1/51780/settings"
}
}
}
},
"_links": {
"self": {
"href": "https://myhost.com/api/v1/company/51780"
},
"settings": {
"href": "https://myhost.com/api/v1/51780/settings"
}
}
}
Which I would like to map to a class like this:
public class Company extends ResourceSupport {
private String name;
private CompanySettings settings;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public CompanySettings getSettings() {
return settings;
}
public void setSettings(CompanySettings settings) {
this.settings = settings;
}
}
And a class for the embedded item like this:
public class CompanySettings extends ResourceSupport {
private String currency;
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}
However I am having no luck getting the embedded item to map to the nested settings object. My code is below.
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<Resource<Company>> responseEntity = restTemplate.exchange("https://uk.bookingbug.com/api/v1/company/51780",
HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Company>>() {
}, Collections.emptyMap());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
Resource<Company> userResource = responseEntity.getBody();
Company company = userResource.getContent();
}
Any help would be greatly appreciated.

Displaying Data with Spring JPA and REST

Following these tutorials 1, 2, I successfully made a RESTful Spring application combined with JPA. Currently, I have 3 drivers in my Driver repository.
My problem is when I go on localhost:8080/driver, it says this:
{
"_embedded" : {
"driver" : [ {
"_links" : {
"self" : {
"href" : "http://localhost:8080/driver/1"
},
"driver" : {
"href" : "http://localhost:8080/driver/1"
}
}
}, {
"_links" : {
"self" : {
"href" : "http://localhost:8080/driver/2"
},
"driver" : {
"href" : "http://localhost:8080/driver/2"
}
}
}, {
"_links" : {
"self" : {
"href" : "http://localhost:8080/driver/3"
},
"driver" : {
"href" : "http://localhost:8080/driver/3"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/driver"
},
"profile" : {
"href" : "http://localhost:8080/profile/driver"
},
"search" : {
"href" : "http://localhost:8080/driver/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 3,
"totalPages" : 1,
"number" : 0
}
}
and when I go onto a particular's drivers page, something like localhost:8080/driver/1, it says this:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/driver/1"
},
"driver" : {
"href" : "http://localhost:8080/driver/1"
}
}
}
In my Driver Entity Class, I have fields like firstName, lastName, telephone and stuff like that. My question is: is there a way I can display on it either localhost:8080/driver or localhost:8080/driver/1? So that it looks similar to this:
{
"firstName" : "Frodo",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
}
I know the fields are properly saved in the database, because I can successfully search for them, but I haven't yet found an example of how to display them, except POSTing with curl.
Thanks in advance to anyone who can help!
Edit: This is my Starter class:
#SpringBootApplication
public class StartServer implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger log = LoggerFactory.getLogger(StartServer.class);
public static void main(String[] args) {
SpringApplication.run(StartServer.class, args);
}
#Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
}
#Bean
public CommandLineRunner demo(DriverRepository repository) {
return (args) -> {
repository.save(new Driver("Jack", "Bauer"));
repository.save(new Driver("JackY", "Aasd"));
repository.save(new Driver("JackMe", "Commou"));
// fetch all customers
log.info("Drivers found with findAll():");
log.info("-------------------------------");
for (Driver driver : repository.findAll()) {
log.info(driver.toString());
}
log.info("");
Driver driver = repository.findOne(1L);
log.info("Customer found with findOne(1L):");
log.info("--------------------------------");
log.info(driver.toString());
log.info("");
// fetch customers by last name
log.info("Driver found with findByLastName('Bauer'):");
log.info("--------------------------------------------");
for (Driver bauer : repository.findByLastName("Bauer")) {
log.info(bauer.toString());
}
log.info("");
};
}
}
And my DriverRepository class:
#RepositoryRestResource(collectionResourceRel = "driver", path = "driver")
public interface DriverRepository extends PagingAndSortingRepository<Driver, Long> {
List<Driver> findByLastName(#Param("name") String name);
}
I do not have a Controller Class for /driver, because the #RepositoryRestResource(collectionResourceRel = "driver", path = "driver") took care of it for me.
My Driver Entity class:
#Entity
public class Driver {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
String firstName;
String lastName;
protected Driver() {
}
public Driver(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return String.format( "Customer[id=%d, firstName='%s', lastName='%s']",
id, firstName, lastName);
}
}

Custom response for root request int the Spring REST HATEOAS with both RepositoryRestResource-s and regular controllers

Let's say I have two repositories:
#RepositoryRestResource(collectionResourceRel = "person", path = "person")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
}
and
#RepositoryRestResource(collectionResourceRel = "person1", path = "person1")
public interface PersonRepository1 extends PagingAndSortingRepository<Person1, Long> {
List<Person1> findByLastName(#Param("name") String name);
}
with one regular controller:
#Controller
public class HelloController {
#RequestMapping("/hello")
#ResponseBody
public HttpEntity<Hello> hello(#RequestParam(value = "name", required = false, defaultValue = "World") String name) {
Hello hello = new Hello(String.format("Hello, %s!", name));
hello.add(linkTo(methodOn(HelloController.class).hello(name)).withSelfRel());
return new ResponseEntity<>(hello, HttpStatus.OK);
}
}
Now, a response for http://localhost:8080/ is:
{
"_links" : {
"person" : {
"href" : "http://localhost:8080/person{?page,size,sort}",
"templated" : true
},
"person1" : {
"href" : "http://localhost:8080/person1{?page,size,sort}",
"templated" : true
}
}
}
but I want to get something like this:
{
"_links" : {
"person" : {
"href" : "http://localhost:8080/person{?page,size,sort}",
"templated" : true
},
"person1" : {
"href" : "http://localhost:8080/person1{?page,size,sort}",
"templated" : true
},
"hello" : {
"href" : "http://localhost:8080/hello?name=World"
}
}
}
#Component
public class HelloResourceProcessor implements ResourceProcessor<RepositoryLinksResource> {
#Override
public RepositoryLinksResource process(RepositoryLinksResource resource) {
resource.add(ControllerLinkBuilder.linkTo(HelloController.class).withRel("hello"));
return resource;
}
}
based on
http://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.customizing-json-output
How to add links to root resource in Spring Data REST?
You need to have a ResourceProcessory for your Person resource registered as a Bean. see https://stackoverflow.com/a/24660635/442773

href link retrieves a not paginated json - spring data rest jpa

I've started working on a REST API using Spring. I'm using the tutorial project gs-accessing-data-rest-initial, which is easy to dowload via Spring Tool Suite, in order to get some stuff working as soon as possible.
I've exposed two related entities (aplicacion and registros_app), using PagingAndSortingRepository and annotated both with #RepositoryRestResource, which enables me to expose entities correctly. The result I'm getting when I query on aplicacion is
**GET http://localhost:8090/aplicacion**
{
"_links" : {
"self" : {
"href" : "http://localhost:8090/aplicacion/{?page,size,sort}",
"templated" : true
}
},
"_embedded" : {
"aplicacion" : [ {
"nombre" : "app1",
"_links" : {
"self" : {
"href" : "http://localhost:8090/aplicacion/2"
},
"registrosApp" : {
"href" : "http://localhost:8090/aplicacion/2/registrosApp"
},
"tipoRegistrosApp" : {
"href" : "http://localhost:8090/aplicacion/2/tipoRegistrosApp"
}
}
}, {
"nombre" : "app2",
"_links" : {
"self" : {
"href" : "http://localhost:8090/aplicacion/1"
},
"registrosApp" : {
"href" : "http://localhost:8090/aplicacion/1/registrosApp"
},
"tipoRegistrosApp" : {
"href" : "http://localhost:8090/aplicacion/1/tipoRegistrosApp"
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
Which is exactly what I've expected to obtain. So, I was expecting to get the same when I navigate to registrosApp, in terms of pagination; however, when I perform a get on any registrosApp link, what I retrieve from the query is
**GET http://localhost:8090/aplicacion/2/registrosApp**
{
"_embedded" : {
"registrosapp" : [ {
"datos" : "{\"FechaInicio\":\"2014-09-16 18:08:44\",\"UsoMemoria\":\"UsedMemory:3 FreeMemory:491 Total Memory:495 Max Memory:989 \",\"InfoPool\":\"Active: 2\"}",
"fecha_hora" : "2014-09-17T14:04:07.000+0000",
"codTipoRegistro" : 1,
"_links" : {
"self" : {
"href" : "http://localhost:8090/registrosApp/605"
},
"aplicacion" : {
"href" : "http://localhost:8090/registrosApp/605/aplicacion"
}
}
},{
"datos" : "{\"FechaInicio\":\"2014-09-16 18:08:44\",\"UsoMemoria\":\"UsedMemory:3 FreeMemory:491 Total Memory:495 Max Memory:989 \",\"InfoPool\":\"Active: 2\"}",
"fecha_hora" : "2014-09-17T14:04:07.000+0000",
"codTipoRegistro" : 1,
"_links" : {
"self" : {
"href" : "http://localhost:8090/registrosApp/667"
},
"aplicacion" : {
"href" : "http://localhost:8090/registrosApp/667/aplicacion"
}
}
} ]
}
}
Which is not actually paginated. I need to get a paginated json when I navigate across links because registrosApp table grows very quickly. ¿What can I do about it?
Here is the code for my registrosApp and aplicacion repository
#RepositoryRestResource(collectionResourceRel = "registrosapp", path = "registrosApp")
public interface RegistrosAppRepository extends PagingAndSortingRepository<RegistrosApp, Long> {
}
#RepositoryRestResource(collectionResourceRel = "aplicacion", path = "aplicacion")
public interface AplicacionRepository extends PagingAndSortingRepository<Aplicacion, Long> {
//List<Person> findByLastName(#Param("name") String name);
}
And those are the entities I've defined
#Entity
#Table(name = "registros_app")
public class RegistrosApp {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long idRegistrosApp;
private String datos;
private Date fecha_hora;
private long codTipoRegistro;
public long getCodTipoRegistro() {
return codTipoRegistro;
}
public void setCodTipoRegistro(long codTipoRegistro) {
this.codTipoRegistro = codTipoRegistro;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "idAplicacion", nullable = false, insertable = false, updatable = false)
Aplicacion aplicacion;
// private long idAplicacion;
/*
* public long getRegistros_app() { return idAplicacion; }
*
* public void setRegistros_app(long registros_app) { this.idAplicacion =
* registros_app; }
*/
public String getDatos() {
return datos;
}
public void setDatos(String datos) {
this.datos = datos;
}
public Date getFecha_hora() {
return fecha_hora;
}
public void setFecha_hora(Date fecha_hora) {
this.fecha_hora = fecha_hora;
}
}
#Entity
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Aplicacion {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long aplicacionId;
private String nombre;
//relaciones uno a varios
//relacion con la tabla registros_app
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "idAplicacion", nullable = false)
private Set<RegistrosApp> registrosApp = null;
//relacion con la tabla tipo_registro_app
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "idApp", nullable = false)
private Set<TipoRegistrosApp> tipoRegistrosApp = null;
public Set<TipoRegistrosApp> getTipoRegistrosApp() {
return tipoRegistrosApp;
}
public void setTipoRegistrosApp(Set<TipoRegistrosApp> tipoRegistrosApp) {
this.tipoRegistrosApp = tipoRegistrosApp;
}
#JsonProperty
public Set<RegistrosApp> getRegistrosApp() {
return registrosApp;
}
/**
* Sets list of <code>Address</code>es.
*/
public void setRegistrosApp(Set<RegistrosApp> rapps) {
this.registrosApp= rapps;
}
#JsonProperty
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
}
You can notice that I have a #onetomany annotation between aplicacion and registrosapp in my entities.
TL;DR When I query directly on registrosapp I get a paginated result as I expect. The problem here is when I navigate between related entities, I'm not getting the pagination information I need. ¿What can I do in order to get pagination when I navigate across entities? Any help with this will be truly appreciated. Thanks in advance.
I will answer myself in order to get this question useful for someone else who is struggling with this problem. This answer is closely related to - Spring Data Rest Pageable Child Collection -
What I've done is to set a method within RegistrosAppRepository, so it stays like this
#RepositoryRestResource(collectionResourceRel = "registrosapp", path = "registrosApp")
public interface RegistrosAppRepository extends PagingAndSortingRepository<RegistrosApp, Long> {
#RestResource(path = "byAplicacion", rel = "byAplicacion")
public Page<RegistrosApp> findByAplicacion(#Param("aplicacion_id") Aplicacion aplicacion, Pageable p);
}
Then I hide the link to registrosApp which appears in aplicacion, by setting the annotation #RestResource(exported=false) before the Set of registrosApp. So the aplicacion entity stays like this
#Entity
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Aplicacion {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long aplicacionId;
private String nombre;
//relaciones uno a varios
//relacion con la tabla registros_app
#RestResource(exported=false)
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "idAplicacion", nullable = false)
private Set<RegistrosApp> registrosApp = null;
//relacion con la tabla tipo_registro_app
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "idApp", nullable = false)
private Set<TipoRegistrosApp> tipoRegistrosApp = null;
public Set<TipoRegistrosApp> getTipoRegistrosApp() {
return tipoRegistrosApp;
}
public void setTipoRegistrosApp(Set<TipoRegistrosApp> tipoRegistrosApp) {
this.tipoRegistrosApp = tipoRegistrosApp;
}
#JsonProperty
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
}
finally, I'm able to navigate between those entities this way:
**GET http://localhost:8090/registrosApp/search/byAplicacion?aplicacion_id=2&page=1&size=1**
{
"_links" : {
"next" : {
"href" : "http://localhost:8090/registrosApp/search/byAplicacion?aplicacion_id=2&page=2&size=1"
},
"prev" : {
"href" : "http://localhost:8090/registrosApp/search/byAplicacion?aplicacion_id=2&page=0&size=1"
},
"self" : {
"href" : "http://localhost:8090/registrosApp/search/byAplicacion?aplicacion_id=2&page=1&size=1{&sort}",
"templated" : true
}
},
"_embedded" : {
"registrosapp" : [ {
"datos" : "{\"FechaInicio\":\"2014-09-16 18:08:44\",\"UsoMemoria\":\"UsedMemory:2 FreeMemory:492 Total Memory:495 Max Memory:989 \",\"InfoPool\":\"Active: 2\"}",
"fecha_hora" : "2014-09-17T14:04:07.000+0000",
"codTipoRegistro" : 1,
"_links" : {
"self" : {
"href" : "http://localhost:8090/registrosApp/593"
},
"aplicacion" : {
"href" : "http://localhost:8090/registrosApp/593/aplicacion"
}
}
} ]
},
"page" : {
"size" : 1,
"totalElements" : 56,
"totalPages" : 56,
"number" : 1
}
}
and the link in aplicacion doesn't show the registrosApp link whithin the json:
**GET http://localhost:8090/aplicacion**
{
"_links" : {
"self" : {
"href" : "http://localhost:8090/aplicacion{?page,size,sort}",
"templated" : true
}
},
"_embedded" : {
"aplicacion" : [ {
"nombre" : "app1",
"_links" : {
"self" : {
"href" : "http://localhost:8090/aplicacion/2"
},
"tipoRegistrosApp" : {
"href" : "http://localhost:8090/aplicacion/2/tipoRegistrosApp"
},
"aplicacion" : {
"href" : "http://localhost:8090/aplicacion/2/aplicacion"
}
}
}, {
"nombre" : "app2",
"_links" : {
"self" : {
"href" : "http://localhost:8090/aplicacion/1"
},
"tipoRegistrosApp" : {
"href" : "http://localhost:8090/aplicacion/1/tipoRegistrosApp"
},
"aplicacion" : {
"href" : "http://localhost:8090/aplicacion/1/aplicacion"
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}

Resources