Skip to content

Commit

Permalink
feat: add BookExceptionHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
oksana-miazina committed May 2, 2024
1 parent a2b50ee commit 92a893a
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 20 deletions.
27 changes: 27 additions & 0 deletions src/main/java/mate/academy/bookstore/config/I18nConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package mate.academy.bookstore.config;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@Configuration
public class I18nConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource
= new ReloadableResourceBundleMessageSource();

messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}

@Bean
public LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}
}
16 changes: 11 additions & 5 deletions src/main/java/mate/academy/bookstore/dto/BookRequestDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@

@Data
public class BookRequestDto {
@NotBlank(message = "Title is required")
private static final String ISBN_PATTERN =
"^(?:ISBN(?:-1[03])?:? )?(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})"
+ "[- 0-9X]{13}$|97[89][0-9]{10}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)"
+ "(?:97[89][- ]?)?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$";
private static final String PRICE_MIN = "0.01";

@NotBlank(message = "{validation.title.notempty}")
private String title;

@NotBlank(message = "Author is required")
@NotBlank(message = "{validation.author.notempty}")
private String author;

@NotBlank(message = "ISBN is required")
@Pattern(regexp = "^\\d{13}$", message = "The ISBN must contain exactly 13 digits")
@NotBlank(message = "{validation.isbn.notempty}")
@Pattern(regexp = ISBN_PATTERN, message = "{validation.isbn.valid}")
private String isbn;

@DecimalMin(value = "0.01", message = "The price must be greater than 0")
@DecimalMin(value = PRICE_MIN, message = "{validation.price.valid}")
private BigDecimal price;

private String description;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package mate.academy.bookstore.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package mate.academy.bookstore.handler;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import mate.academy.bookstore.exception.EntityNotFoundException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class BookControllerExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseBody
public ResponseEntity<Object> handleEntityNotFoundException(EntityNotFoundException ex) {
return getResponseEntity(HttpStatus.NOT_FOUND, ex.getMessage());
}

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseEntity<Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach(error -> {
Map.Entry<String, String> errorMessage = getErrorMessage(error);
errors.put(errorMessage.getKey(), errorMessage.getValue());
});

return getResponseEntity(HttpStatus.BAD_REQUEST, errors);
}

@ExceptionHandler(DataIntegrityViolationException.class)
@ResponseBody
public ResponseEntity<Object> handleDataIntegrityViolationException(
DataIntegrityViolationException ex) {
return getResponseEntity(HttpStatus.CONFLICT, ex.getMessage());
}

private Map.Entry<String, String> getErrorMessage(ObjectError e) {
if (e instanceof FieldError fieldError) {
String field = fieldError.getField();
String message = e.getDefaultMessage();
return Map.entry(field, message);
}
return Map.entry("", e.getDefaultMessage());
}

private ResponseEntity<Object> getResponseEntity(HttpStatus status, Object errors) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("success", status.is2xxSuccessful());
body.put("errors", errors);
return new ResponseEntity<>(body, status);
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package mate.academy.bookstore.repository;

import java.util.Optional;
import mate.academy.bookstore.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BookRepository extends JpaRepository<Book, Long> {
Optional<Book> findByIsbn(String isbn);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import mate.academy.bookstore.model.Book;
import mate.academy.bookstore.repository.BookRepository;
import mate.academy.bookstore.service.BookService;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;

@Service
Expand All @@ -19,6 +20,10 @@ public class BookServiceImpl implements BookService {

@Override
public BookDto save(BookRequestDto bookDto) {
bookRepository.findByIsbn(bookDto.getIsbn())
.ifPresent(s -> {
throw new DataIntegrityViolationException("Book already exists.");
});
Book book = bookMapper.toModel(bookDto);
Book savedBook = bookRepository.save(book);
return bookMapper.toDto(savedBook);
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/messages.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
validation.title.notempty=Title is required
validation.author.notempty=Author is required
validation.isbn.notempty=The ISBN is required
validation.isbn.valid=The ISBN is not valid
validation.price.valid=The price must be greater than 0

0 comments on commit 92a893a

Please sign in to comment.