Polishing.

This commit is contained in:
Greg Turnquist
2019-03-03 11:05:27 -06:00
parent 15db5a0513
commit e8de8268ad
40 changed files with 443 additions and 463 deletions

View File

@@ -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"));

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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> {}

View File

@@ -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();
}
}