In this chapter we are going to create service layer which exposes backend functionality.
Your first task is to implement a simple PersonService. This service will manage basic CRUD operations for a Person entity. After implementing the service, you will write test cases to verify the service’s functionality.
-
Create a package named
com.capgemini.training.todo.task.service. -
Within this package, create a class named
PersonService. -
Use annotations like
@RestController,@RequestMapping,@GetMapping,@PostMapping, and@DeleteMappingto define your RESTful service. -
Map the service to the
/personpath, so it will be availablu underhttp://localhost:8080/person/@RestController @RequestMapping("person") @RequiredArgsConstructor public class PersonService { // Your code here }
-
Implement CRUD operations to list, get, create and delete a
Personusing the use cases implemented in the business logic layer. -
Use annotations like
@PathVariableto map the path variable to the method parameter. -
Use annotation
@RequestBodyto define the parameters representing the request parameters (e.g. for thePOSTmethod)final FindPersonUc findPersonUc; final ManagePersonUc managePersonUc; @GetMapping("/{id}") PersonEto findPerson(@PathVariable("id") @NotNull Long id) { return findPersonUc.findPerson(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Person with id " + id + " does not exist.")); } // TODO annotate List<PersonEto> findAllPersons() { // TODO Implement me! return null; } // TODO annotate PersonEto savePerson(PersonEto personEto) { // TODO Implement me! return null; } // TODO annotate void deletePerson(@NotNull Long id) { // TODO Implement me! return null; }
The service method implemented by findPerson can be accessed under following url using GET request:
http://localhost:8080/person/{id}Test the implemented services using Postman (or your favourite testing tool)
The other methods can be tested in the similar way
-
Annotate the test class using
@WebMvcTest. It will define a Spring MVC test that focuses only on Spring MVC components. -
Use
MockMvcto simulate HTTP requests. Use the factory methods (likeget,post,status) fromMockMvcResultMatchers -
Use Mockito to mock the service dependencies from the logic layer.
-
Use
@MockBeanto inject the mocked dependencies. -
Below is an example of how to test the
findAllPersonsmethod:@WebMvcTest(PersonService.class) public class PersonServiceTest { @Autowired private MockMvc mockMvc; @MockBean private FindPersonUc findPersonUc; @Test public void findPerson_ShouldReturnPerson() throws Exception { Long personId = 1L; PersonEto person = PersonEto.builder().id(personId).version(1).email("test@example.com").build(); given(findPersonUc.findPerson(personId)).willReturn(Optional.of(person)); mockMvc.perform(get("/person/{id}", personId).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(person.id())) .andExpect(jsonPath("$.email").value(person.email())); } // Here other tests }
-
Write test cases for each CRUD operation you have implemented in the
PersonService
After you have successfully completed the PersonService, proceed to implement TaskItemService and TaskListService with their respective test cases using the use cases you have implemented in the logic layer.
Follow the same steps as in the previous service for both TaskItemService and TaskListService. Ensure you implement CRUD operations and write corresponding test cases for each method.
Usually the validation of the parameters should be performed on the service layer to prevent requests which are not valid.
In this task you can add input validation to your services. Utilize annotations like @Validated in your service class and @Valid and @NotNull in your service methods to enforce constraints on incoming data.
Please follow Bean validation using Hibernate Validator in Task Service - Business Logic Layer for more details.
When writing your test cases, you might need to send JSON payloads. Use Jackson’s ObjectMapper to serialize Java objects into JSON strings:
ObjectMapper objectMapper = new ObjectMapper();
PersonEto newPerson = PersonEto.builder().id(null).version(0).email("test@example.com").build();
String newPersonJson = objectMapper.writeValueAsString(newPerson);
mockMvc.perform(
post("/person/").contentType(MediaType.APPLICATION_JSON).content(newPersonJson))
.andExpect(...)
...
)If you encounter InvalidDefinitionException with Java 8 date/time types, like java.time.Instant, you can fix this by registering the JavaTimeModule with your ObjectMapper:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());This allows your ObjectMapper to correctly serialize and deserialize Java 8 date/time types.

