Polishing.
This commit is contained in:
@@ -28,13 +28,14 @@ import org.springframework.stereotype.Component;
|
||||
class DatabaseLoader {
|
||||
|
||||
/**
|
||||
* Use Spring to inject a {@link EmployeeRepository} that can then load data. Since this will run
|
||||
* only after the app is operational, the database will be up.
|
||||
* Use Spring to inject a {@link EmployeeRepository} that can then load data. Since this will run only after the app
|
||||
* is operational, the database will be up.
|
||||
*
|
||||
* @param repository
|
||||
*/
|
||||
@Bean
|
||||
CommandLineRunner init(EmployeeRepository repository) {
|
||||
|
||||
return args -> {
|
||||
repository.save(new Employee("Frodo", "Baggins", "ring bearer"));
|
||||
repository.save(new Employee("Bilbo", "Baggins", "burglar"));
|
||||
|
||||
@@ -25,18 +25,14 @@ import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* Domain object representing a company employee. Project Lombok keeps actual code at a minimum.
|
||||
*
|
||||
* {@code @Data} - Generates getters, setters, toString, hash, and equals functions
|
||||
* {@code @Entity} - JPA annotation to flag this class for DB persistence
|
||||
* {@code @NoArgsConstructor} - Create a constructor with no args to support JPA
|
||||
* Domain object representing a company employee. Project Lombok keeps actual code at a minimum. {@code @Data} -
|
||||
* Generates getters, setters, toString, hash, and equals functions {@code @Entity} - JPA annotation to flag this class
|
||||
* for DB persistence {@code @NoArgsConstructor} - Create a constructor with no args to support JPA
|
||||
* {@code @AllArgsConstructor} - Create a constructor with all args to support testing
|
||||
*
|
||||
* {@code @JsonIgnoreProperties(ignoreUnknow=true)}
|
||||
* When converting JSON to Java, ignore any unrecognized attributes. This is critical for REST because it
|
||||
* encourages adding new fields in later versions that won't break. It also allows things like _links to be
|
||||
* ignore as well, meaning HAL documents can be fetched and later posted to the server without adjustment.
|
||||
*
|
||||
* {@code @JsonIgnoreProperties(ignoreUnknow=true)} When converting JSON to Java, ignore any unrecognized attributes.
|
||||
* This is critical for REST because it encourages adding new fields in later versions that won't break. It also allows
|
||||
* things like _links to be ignore as well, meaning HAL documents can be fetched and later posted to the server without
|
||||
* adjustment.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@@ -46,8 +42,7 @@ import javax.persistence.Id;
|
||||
@AllArgsConstructor
|
||||
class Employee {
|
||||
|
||||
@Id @GeneratedValue
|
||||
private Long id;
|
||||
@Id @GeneratedValue private Long id;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String role;
|
||||
|
||||
@@ -23,10 +23,10 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.springframework.hateoas.CollectionModel;
|
||||
import org.springframework.hateoas.EntityModel;
|
||||
import org.springframework.hateoas.IanaLinkRelations;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.EntityModel;
|
||||
import org.springframework.hateoas.CollectionModel;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -50,21 +50,21 @@ class EmployeeController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up all employees, and transform them into a REST collection resource.
|
||||
* Then return them through Spring Web's {@link ResponseEntity} fluent API.
|
||||
* Look up all employees, and transform them into a REST collection resource. Then return them through Spring Web's
|
||||
* {@link ResponseEntity} fluent API.
|
||||
*/
|
||||
@GetMapping("/employees")
|
||||
ResponseEntity<CollectionModel<EntityModel<Employee>>> findAll() {
|
||||
|
||||
List<EntityModel<Employee>> employees = StreamSupport.stream(repository.findAll().spliterator(), false)
|
||||
.map(employee -> new EntityModel<>(employee,
|
||||
linkTo(methodOn(EmployeeController.class).findOne(employee.getId())).withSelfRel(),
|
||||
linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees")))
|
||||
.collect(Collectors.toList());
|
||||
.map(employee -> new EntityModel<>(employee, //
|
||||
linkTo(methodOn(EmployeeController.class).findOne(employee.getId())).withSelfRel(), //
|
||||
linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees"))) //
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ResponseEntity.ok(
|
||||
new CollectionModel<>(employees,
|
||||
linkTo(methodOn(EmployeeController.class).findAll()).withSelfRel()));
|
||||
return ResponseEntity.ok( //
|
||||
new CollectionModel<>(employees, //
|
||||
linkTo(methodOn(EmployeeController.class).findAll()).withSelfRel()));
|
||||
}
|
||||
|
||||
@PostMapping("/employees")
|
||||
@@ -73,32 +73,32 @@ class EmployeeController {
|
||||
try {
|
||||
Employee savedEmployee = repository.save(employee);
|
||||
|
||||
EntityModel<Employee> employeeResource = new EntityModel<>(savedEmployee,
|
||||
linkTo(methodOn(EmployeeController.class).findOne(savedEmployee.getId())).withSelfRel());
|
||||
EntityModel<Employee> employeeResource = new EntityModel<>(savedEmployee, //
|
||||
linkTo(methodOn(EmployeeController.class).findOne(savedEmployee.getId())).withSelfRel());
|
||||
|
||||
return ResponseEntity
|
||||
.created(new URI(employeeResource.getRequiredLink(IanaLinkRelations.SELF).getHref()))
|
||||
.body(employeeResource);
|
||||
return ResponseEntity //
|
||||
.created(new URI(employeeResource.getRequiredLink(IanaLinkRelations.SELF).getHref())) //
|
||||
.body(employeeResource);
|
||||
} catch (URISyntaxException e) {
|
||||
return ResponseEntity.badRequest().body("Unable to create " + employee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a single {@link Employee} and transform it into a REST resource. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
* Look up a single {@link Employee} and transform it into a REST resource. Then return it through Spring Web's
|
||||
* {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping("/employees/{id}")
|
||||
ResponseEntity<EntityModel<Employee>> findOne(@PathVariable long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
.map(employee -> new EntityModel<>(employee,
|
||||
linkTo(methodOn(EmployeeController.class).findOne(employee.getId())).withSelfRel(),
|
||||
linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees")))
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
return repository.findById(id) //
|
||||
.map(employee -> new EntityModel<>(employee, //
|
||||
linkTo(methodOn(EmployeeController.class).findOne(employee.getId())).withSelfRel(), //
|
||||
linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees"))) //
|
||||
.map(ResponseEntity::ok) //
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,9 +118,7 @@ class EmployeeController {
|
||||
Link newlyCreatedLink = linkTo(methodOn(EmployeeController.class).findOne(id)).withSelfRel();
|
||||
|
||||
try {
|
||||
return ResponseEntity.noContent()
|
||||
.location(new URI(newlyCreatedLink.getHref()))
|
||||
.build();
|
||||
return ResponseEntity.noContent().location(new URI(newlyCreatedLink.getHref())).build();
|
||||
} catch (URISyntaxException e) {
|
||||
return ResponseEntity.badRequest().body("Unable to update " + employeeToUpdate);
|
||||
}
|
||||
|
||||
@@ -22,5 +22,4 @@ import org.springframework.data.repository.CrudRepository;
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
interface EmployeeRepository extends CrudRepository<Employee, Long> {
|
||||
}
|
||||
interface EmployeeRepository extends CrudRepository<Employee, Long> {}
|
||||
|
||||
@@ -42,37 +42,35 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
@WebMvcTest(EmployeeController.class)
|
||||
public class EmployeeControllerTests {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private EmployeeRepository repository;
|
||||
@MockBean private EmployeeRepository repository;
|
||||
|
||||
@Test
|
||||
public void getShouldFetchAHalDocument() throws Exception {
|
||||
|
||||
given(repository.findAll()).willReturn(
|
||||
Arrays.asList(
|
||||
new Employee(1L,"Frodo", "Baggins", "ring bearer"),
|
||||
new Employee(2L,"Bilbo", "Baggins", "burglar")));
|
||||
given(repository.findAll()).willReturn( //
|
||||
Arrays.asList( //
|
||||
new Employee(1L, "Frodo", "Baggins", "ring bearer"), //
|
||||
new Employee(2L, "Bilbo", "Baggins", "burglar")));
|
||||
|
||||
mvc.perform(get("/employees").accept(MediaTypes.HAL_JSON_VALUE))
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].id", is(1)))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].firstName", is("Frodo")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].lastName", is("Baggins")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].role", is("ring bearer")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0]._links.self.href", is("http://localhost/employees/1")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0]._links.employees.href", is("http://localhost/employees")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].id", is(2)))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].firstName", is("Bilbo")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].lastName", is("Baggins")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].role", is("burglar")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1]._links.self.href", is("http://localhost/employees/2")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1]._links.employees.href", is("http://localhost/employees")))
|
||||
.andExpect(jsonPath("$._links.self.href", is("http://localhost/employees")))
|
||||
.andReturn();
|
||||
mvc.perform(get("/employees").accept(MediaTypes.HAL_JSON_VALUE)) //
|
||||
.andDo(print()) //
|
||||
.andExpect(status().isOk()) //
|
||||
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].id", is(1)))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].firstName", is("Frodo")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].lastName", is("Baggins")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0].role", is("ring bearer")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0]._links.self.href", is("http://localhost/employees/1")))
|
||||
.andExpect(jsonPath("$._embedded.employees[0]._links.employees.href", is("http://localhost/employees")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].id", is(2)))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].firstName", is("Bilbo")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].lastName", is("Baggins")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1].role", is("burglar")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1]._links.self.href", is("http://localhost/employees/2")))
|
||||
.andExpect(jsonPath("$._embedded.employees[1]._links.employees.href", is("http://localhost/employees")))
|
||||
.andExpect(jsonPath("$._links.self.href", is("http://localhost/employees"))) //
|
||||
.andReturn();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user