Skip to content

Commit 6794b7b

Browse files
committed
refactor!: move validation from Entity to DTO
1 parent 01d0050 commit 6794b7b

3 files changed

Lines changed: 36 additions & 62 deletions

File tree

src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/BooksController.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ public ResponseEntity<String> post(@RequestBody BookDTO bookDTO) {
8989
@GetMapping("/books/{isbn}")
9090
@Operation(summary = "Retrieves a book by its ID")
9191
@ApiResponses(value = {
92-
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json",
93-
schema = @Schema(implementation = BookDTO.class))),
92+
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema =
93+
@Schema(implementation = BookDTO.class))),
9494
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content)
9595
})
9696
public ResponseEntity<BookDTO> getByIsbn(@PathVariable String isbn) {
@@ -105,8 +105,8 @@ public ResponseEntity<BookDTO> getByIsbn(@PathVariable String isbn) {
105105
@GetMapping("/books")
106106
@Operation(summary = "Retrieves all books")
107107
@ApiResponses(value = {
108-
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json",
109-
schema = @Schema(implementation = BookDTO[].class)))
108+
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema =
109+
@Schema(implementation = BookDTO[].class)))
110110
})
111111
public ResponseEntity<List<BookDTO>> getAll() {
112112
List<BookDTO> books = service.retrieveAll();
@@ -125,7 +125,7 @@ public ResponseEntity<List<BookDTO>> getAll() {
125125
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content)
126126
})
127127
public ResponseEntity<String> put(@RequestBody BookDTO bookDTO) {
128-
if (service.retrieveByIsbn(bookDTO.getIsbn()) != null) {
128+
if (service.retrieveByIsbn(bookDTO.getIsbn()) != null) {
129129
if (service.update(bookDTO)) {
130130
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
131131
} else {

src/main/java/ar/com/nanotaboada/java/samples/spring/boot/services/BooksService.java

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ public BooksService(BooksRepository repository, Validator validator, ModelMapper
3535

3636
@CachePut(value = "books", key = "#bookDTO.isbn")
3737
public boolean create(BookDTO bookDTO) {
38-
boolean created = false;
39-
Book book = mapper.map(bookDTO, Book.class);
40-
if (validator.validate(book).isEmpty() && !repository.existsById(book.getIsbn())) {
38+
if (validator.validate(bookDTO).isEmpty()
39+
&& !repository.existsById(bookDTO.getIsbn())) {
40+
Book book = mapper.map(bookDTO, Book.class);
4141
repository.save(book);
42-
created = true;
42+
return true;
4343
}
44-
return created;
44+
return false;
4545
}
4646

4747
/* --------------------------------------------------------------------------------------------
@@ -50,21 +50,16 @@ public boolean create(BookDTO bookDTO) {
5050

5151
@Cacheable(value = "books", key = "#isbn")
5252
public BookDTO retrieveByIsbn(String isbn) {
53-
BookDTO bookDTO = null;
54-
Book book = repository.findByIsbn(isbn).orElse(null);
55-
if (book != null) {
56-
bookDTO = mapper.map(book, BookDTO.class);
57-
}
58-
return bookDTO;
53+
return repository.findByIsbn(isbn)
54+
.map(book -> mapper.map(book, BookDTO.class))
55+
.orElse(null);
5956
}
6057

6158
@Cacheable(value = "books")
6259
public List<BookDTO> retrieveAll() {
63-
List<Book> books = StreamSupport.stream(repository.findAll().spliterator(), false)
64-
.collect(Collectors.toList());
65-
return books.stream()
66-
.map(book -> mapper.map(book, BookDTO.class))
67-
.collect(Collectors.toList());
60+
return StreamSupport.stream(repository.findAll().spliterator(), false)
61+
.map(book -> mapper.map(book, BookDTO.class))
62+
.collect(Collectors.toList());
6863
}
6964

7065
/* --------------------------------------------------------------------------------------------
@@ -73,13 +68,13 @@ public List<BookDTO> retrieveAll() {
7368

7469
@CachePut(value = "books", key = "#bookDTO.isbn")
7570
public boolean update(BookDTO bookDTO) {
76-
boolean updated = false;
77-
Book book = mapper.map(bookDTO, Book.class);
78-
if (validator.validate(book).isEmpty() && repository.existsById(book.getIsbn())) {
71+
if (validator.validate(bookDTO).isEmpty()
72+
&& repository.existsById(bookDTO.getIsbn())) {
73+
Book book = mapper.map(bookDTO, Book.class);
7974
repository.save(book);
80-
updated = true;
75+
return true;
8176
}
82-
return updated;
77+
return false;
8378
}
8479

8580
/* --------------------------------------------------------------------------------------------
@@ -88,11 +83,10 @@ public boolean update(BookDTO bookDTO) {
8883

8984
@CacheEvict(value = "books", key = "#isbn")
9085
public boolean delete(String isbn) {
91-
boolean deleted = false;
92-
if (!isbn.isBlank() && repository.existsById(isbn)) {
86+
if (repository.existsById(isbn)) {
9387
repository.deleteById(isbn);
94-
deleted = true;
88+
return true;
9589
}
96-
return deleted;
90+
return false;
9791
}
9892
}

src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/services/BooksServiceTests.java

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,11 @@ void givenCreate_whenBookIsInvalid_thenShouldNeverSaveBookIntoRepositoryAndRetur
5757
// Arrange
5858
boolean result = false;
5959
BookDTO bookDTO = BookDTOsBuilder.buildOneInvalid();
60-
Book book = BooksBuilder.buildOneInvalid();
6160
// Simplify creation of ConstraintViolationExceptions
6261
// https://hibernate.atlassian.net/browse/BVAL-198
63-
Set<? extends ConstraintViolation<?>> errors = new HashSet<ConstraintViolation<Book>>();
62+
Set<? extends ConstraintViolation<?>> errors = new HashSet<ConstraintViolation<BookDTO>>();
6463
Mockito
65-
.when(mapper.map(bookDTO, Book.class))
66-
.thenReturn(book);
67-
Mockito
68-
.when(validator.validate(any(Book.class)))
64+
.when(validator.validate(any(BookDTO.class)))
6965
.thenThrow(new ConstraintViolationException(errors));
7066
// Act
7167
try {
@@ -74,7 +70,6 @@ void givenCreate_whenBookIsInvalid_thenShouldNeverSaveBookIntoRepositoryAndRetur
7470
// Assert
7571
assertThat(exception).isInstanceOf(ConstraintViolationException.class);
7672
} finally {
77-
verify(mapper, times(1)).map(bookDTO, Book.class);
7873
verify(repository, never()).save(any(Book.class));
7974
assertThat(result).isFalse();
8075
}
@@ -85,21 +80,16 @@ void givenCreate_whenBookIsValidButAlreadyExistsInRepository_thenShouldNeverSave
8580
// Arrange
8681
boolean result = false;
8782
BookDTO bookDTO = BookDTOsBuilder.buildOneValid();
88-
Book book = BooksBuilder.buildOneValid();
89-
Set<ConstraintViolation<Book>> errors = new HashSet<ConstraintViolation<Book>>();
83+
Set<ConstraintViolation<BookDTO>> errors = new HashSet<ConstraintViolation<BookDTO>>();
9084
Mockito
91-
.when(mapper.map(bookDTO, Book.class))
92-
.thenReturn(book);
93-
Mockito
94-
.when(validator.validate(any(Book.class)))
85+
.when(validator.validate(any(BookDTO.class)))
9586
.thenReturn(errors);
9687
Mockito
9788
.when(repository.existsById(anyString()))
9889
.thenReturn(true);
9990
// Act
10091
result = service.create(bookDTO);
10192
// Assert
102-
verify(mapper, times(1)).map(bookDTO, Book.class);
10393
assertThat(errors).isEmpty();
10494
verify(repository, never()).save(any(Book.class));
10595
assertThat(result).isFalse();
@@ -111,12 +101,12 @@ void givenCreate_whenBookIsValidAndDoesNotExistInRepository_thenShouldSaveBookIn
111101
boolean result = false;
112102
BookDTO bookDTO = BookDTOsBuilder.buildOneValid();
113103
Book book = BooksBuilder.buildOneValid();
114-
Set<ConstraintViolation<Book>> errors = new HashSet<ConstraintViolation<Book>>();
104+
Set<ConstraintViolation<BookDTO>> errors = new HashSet<ConstraintViolation<BookDTO>>();
115105
Mockito
116106
.when(mapper.map(bookDTO, Book.class))
117107
.thenReturn(book);
118108
Mockito
119-
.when(validator.validate(any(Book.class)))
109+
.when(validator.validate(any(BookDTO.class)))
120110
.thenReturn(errors);
121111
Mockito
122112
.when(repository.existsById(anyString()))
@@ -200,15 +190,11 @@ void givenUpdate_whenBookIsInvalid_thenShouldNeverSaveBookIntoRepositoryAndRetur
200190
// Arrange
201191
boolean result = false;
202192
BookDTO bookDTO = BookDTOsBuilder.buildOneInvalid();
203-
Book book = BooksBuilder.buildOneInvalid();
204193
// Simplify creation of ConstraintViolationExceptions
205194
// https://hibernate.atlassian.net/browse/BVAL-198
206-
Set<? extends ConstraintViolation<?>> errors = new HashSet<ConstraintViolation<Book>>();
195+
Set<? extends ConstraintViolation<?>> errors = new HashSet<ConstraintViolation<BookDTO>>();
207196
Mockito
208-
.when(mapper.map(bookDTO, Book.class))
209-
.thenReturn(book);
210-
Mockito
211-
.when(validator.validate(any(Book.class)))
197+
.when(validator.validate(any(BookDTO.class)))
212198
.thenThrow(new ConstraintViolationException(errors));
213199
// Act
214200
try {
@@ -217,7 +203,6 @@ void givenUpdate_whenBookIsInvalid_thenShouldNeverSaveBookIntoRepositoryAndRetur
217203
// Assert
218204
assertThat(exception).isInstanceOf(ConstraintViolationException.class);
219205
} finally {
220-
verify(mapper, times(1)).map(bookDTO, Book.class);
221206
verify(repository, never()).save(any(Book.class));
222207
assertThat(result).isFalse();
223208
}
@@ -229,12 +214,12 @@ void givenUpdate_whenBookIsValidAndExistInRepository_thenShouldSaveBookIntoRepos
229214
boolean result = false;
230215
BookDTO bookDTO = BookDTOsBuilder.buildOneValid();
231216
Book book = BooksBuilder.buildOneValid();
232-
Set<ConstraintViolation<Book>> errors = new HashSet<ConstraintViolation<Book>>();
217+
Set<ConstraintViolation<BookDTO>> errors = new HashSet<ConstraintViolation<BookDTO>>();
233218
Mockito
234219
.when(mapper.map(bookDTO, Book.class))
235220
.thenReturn(book);
236221
Mockito
237-
.when(validator.validate(any(Book.class)))
222+
.when(validator.validate(any(BookDTO.class)))
238223
.thenReturn(errors);
239224
Mockito
240225
.when(repository.existsById(anyString()))
@@ -253,21 +238,16 @@ void givenUpdate_whenBookIsValidButDoesNotExistInRepository_thenShouldNeverSaveB
253238
// Arrange
254239
boolean result = false;
255240
BookDTO bookDTO = BookDTOsBuilder.buildOneValid();
256-
Book book = BooksBuilder.buildOneValid();
257-
Set<ConstraintViolation<Book>> errors = new HashSet<ConstraintViolation<Book>>();
241+
Set<ConstraintViolation<BookDTO>> errors = new HashSet<ConstraintViolation<BookDTO>>();
258242
Mockito
259-
.when(mapper.map(bookDTO, Book.class))
260-
.thenReturn(book);
261-
Mockito
262-
.when(validator.validate(any(Book.class)))
243+
.when(validator.validate(any(BookDTO.class)))
263244
.thenReturn(errors);
264245
Mockito
265246
.when(repository.existsById(anyString()))
266247
.thenReturn(false);
267248
// Act
268249
result = service.update(bookDTO);
269250
// Assert
270-
verify(mapper, times(1)).map(bookDTO, Book.class);
271251
assertThat(errors).isEmpty();
272252
verify(repository, never()).save(any(Book.class));
273253
assertThat(result).isFalse();

0 commit comments

Comments
 (0)