0

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"
            }
        }
    }
uı6ʎɹnɯ ꞁəıuɐp
  • 3,431
  • 3
  • 40
  • 49

2 Answers2

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.

Marc Tarin
  • 3,109
  • 17
  • 49
1

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.

evdelacruz
  • 314
  • 3
  • 4