diff --git a/schools/javadocs/com/lambdaschool/zoos/services/ZooServiceImpl.html b/schools/javadocs/com/lambdaschool/zoos/services/ZooServiceImpl.html index 10bef294..845a2d71 100644 --- a/schools/javadocs/com/lambdaschool/zoos/services/ZooServiceImpl.html +++ b/schools/javadocs/com/lambdaschool/zoos/services/ZooServiceImpl.html @@ -376,7 +376,7 @@

update

delete

@Transactional
 public void delete​(long id)
-            throws javax.persistence.EntityNotFoundException
+ throws javax.persistence.ResourceNotFoundException
Description copied from interface: ZooService
Deletes the course record, it student course combinations, and its telephone items from the database based off of the provided primary key
@@ -385,7 +385,7 @@

delete

Parameters:
id - id The primary key (long) of the course you seek.
Throws:
-
javax.persistence.EntityNotFoundException
+
javax.persistence.ResourceNotFoundException
@@ -438,7 +438,7 @@

saveZooAnimalCombo

  • findZooByLikeName

    public java.util.ArrayList<Zoo> findZooByLikeName​(java.lang.String name)
    -                                           throws javax.persistence.EntityNotFoundException
    + throws javax.persistence.ResourceNotFoundException
    Description copied from interface: ZooService
    A list of all zoos whose name contains the given substring A Stretch Goal
    @@ -450,7 +450,7 @@

    findZooByLikeName

    Returns:
    List of zoos whose name contains the given substring
    Throws:
    -
    javax.persistence.EntityNotFoundException
    +
    javax.persistence.ResourceNotFoundException
  • diff --git a/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java b/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java new file mode 100644 index 00000000..d363ce08 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java @@ -0,0 +1,34 @@ +package com.lambdaschool.schools.exceptions; + +import com.lambdaschool.schools.services.HelperFunctions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.WebRequest; + +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; + +@Component +public class CustomErrorDetails extends DefaultErrorAttributes { + @Autowired + private HelperFunctions helperFunctions; + + @Override + public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { + Map errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace); + + Map rtnAttributes = new LinkedHashMap<>(); + + rtnAttributes.put("title", errorAttributes.get("error")); + rtnAttributes.put("status", errorAttributes.get("status")); + rtnAttributes.put("detail", errorAttributes.get("message")); + rtnAttributes.put("timestamp", new Date()); + rtnAttributes.put("developerMessage", "path: " + errorAttributes.get("path")); + + rtnAttributes.put("errors", helperFunctions.getValidationErrors(this.getError(webRequest))); + + return rtnAttributes; + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceFoundException.java b/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceFoundException.java new file mode 100644 index 00000000..082c71cc --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceFoundException.java @@ -0,0 +1,7 @@ +package com.lambdaschool.schools.exceptions; + +public class ResourceFoundException extends RuntimeException{ + public ResourceFoundException(String message) { + super("Found an issue with School: " + message); + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceNotFoundException.java b/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceNotFoundException.java new file mode 100644 index 00000000..6d59442f --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceNotFoundException.java @@ -0,0 +1,8 @@ +package com.lambdaschool.schools.exceptions; + + +public class ResourceNotFoundException extends RuntimeException{ + public ResourceNotFoundException(String message) { + super("Found an error with School: " + message); + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/handlers/RestExceptionHandler.java b/schools/src/main/java/com/lambdaschool/schools/handlers/RestExceptionHandler.java new file mode 100644 index 00000000..e296e2ed --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/handlers/RestExceptionHandler.java @@ -0,0 +1,74 @@ +package com.lambdaschool.schools.handlers; + +import com.lambdaschool.schools.exceptions.ResourceFoundException; +import com.lambdaschool.schools.exceptions.ResourceNotFoundException; +import com.lambdaschool.schools.models.ErrorDetail; +import com.lambdaschool.schools.services.HelperFunctions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MissingPathVariableException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.NoHandlerFoundException; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.util.Date; + +@RestControllerAdvice +@Order(Ordered.HIGHEST_PRECEDENCE) +public class RestExceptionHandler extends ResponseEntityExceptionHandler { + @Autowired + private HelperFunctions helperFunctions; + + public RestExceptionHandler() { + super(); + } + + @Override + protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { + ErrorDetail errorDetail = new ErrorDetail(); + + errorDetail.setTimestamp(new Date()); + errorDetail.setTitle("Rest Internal Exception"); + errorDetail.setStatus(status.value()); + errorDetail.setDetail("Found an error with School: " + ex.getMessage()); + errorDetail.setDeveloperMessage(ex.getClass().getName()); + errorDetail.setErrors(helperFunctions.getValidationErrors(ex)); + + return new ResponseEntity<>(errorDetail, null, status); + } + + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFoundException(ResourceNotFoundException rnfe) { + ErrorDetail errorDetail = new ErrorDetail(); + + errorDetail.setTimestamp(new Date()); + errorDetail.setTitle("Resource Not Found"); + errorDetail.setStatus(HttpStatus.NOT_FOUND.value()); + errorDetail.setDetail(rnfe.getMessage()); + errorDetail.setDeveloperMessage(rnfe.getClass().getName()); + errorDetail.setErrors(helperFunctions.getValidationErrors(rnfe)); + + return new ResponseEntity<>(errorDetail, null, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(ResourceFoundException.class) + public ResponseEntity handleResourceFoundException(ResourceNotFoundException rnfe) { + ErrorDetail errorDetail = new ErrorDetail(); + + errorDetail.setTimestamp(new Date()); + errorDetail.setTitle("Unexpected Resource"); + errorDetail.setStatus(HttpStatus.BAD_REQUEST.value()); + errorDetail.setDetail(rnfe.getMessage()); + errorDetail.setDeveloperMessage(rnfe.getClass().getName()); + errorDetail.setErrors(helperFunctions.getValidationErrors(rnfe)); + + return new ResponseEntity<>(errorDetail, null, HttpStatus.BAD_REQUEST); + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/models/ErrorDetail.java b/schools/src/main/java/com/lambdaschool/schools/models/ErrorDetail.java new file mode 100644 index 00000000..fd8a97b3 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/models/ErrorDetail.java @@ -0,0 +1,65 @@ +package com.lambdaschool.schools.models; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class ErrorDetail { + private String title; + private int status; + private String detail; + private Date timestamp; + private String developerMessage; + private List errors = new ArrayList<>(); + + public ErrorDetail() { + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public Date getTimestamp() { + return timestamp; + } + + public void setTimestamp(Date timestamp) { + this.timestamp = timestamp; + } + + public String getDeveloperMessage() { + return developerMessage; + } + + public void setDeveloperMessage(String developerMessage) { + this.developerMessage = developerMessage; + } + + public List getErrors() { + return errors; + } + + public void setErrors(List errors) { + this.errors = errors; + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/models/ValidationError.java b/schools/src/main/java/com/lambdaschool/schools/models/ValidationError.java new file mode 100644 index 00000000..22af917f --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/models/ValidationError.java @@ -0,0 +1,30 @@ +package com.lambdaschool.schools.models; + +public class ValidationError { + private String fieldName; + private String message; + + public ValidationError() { + } + + public ValidationError(String fieldName, String message) { + this.fieldName = fieldName; + this.message = message; + } + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/services/CoursesServiceImpl.java b/schools/src/main/java/com/lambdaschool/schools/services/CoursesServiceImpl.java index 77861321..5682d2a5 100644 --- a/schools/src/main/java/com/lambdaschool/schools/services/CoursesServiceImpl.java +++ b/schools/src/main/java/com/lambdaschool/schools/services/CoursesServiceImpl.java @@ -1,5 +1,6 @@ package com.lambdaschool.schools.services; +import com.lambdaschool.schools.exceptions.ResourceNotFoundException; import com.lambdaschool.schools.models.Course; import com.lambdaschool.schools.models.Instructor; import com.lambdaschool.schools.models.StudCourses; @@ -11,7 +12,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.persistence.EntityNotFoundException; import java.util.ArrayList; import java.util.List; @@ -58,7 +58,7 @@ public List findAll() public Course findCourseById(long id) { return courserepos.findById(id) - .orElseThrow(() -> new EntityNotFoundException("Course id " + id + " not found!")); + .orElseThrow(() -> new ResourceNotFoundException("Course id " + id + " not found!")); } @Transactional @@ -66,7 +66,7 @@ public Course findCourseById(long id) public void delete(long id) { courserepos.findById(id) - .orElseThrow(() -> new EntityNotFoundException("Course id " + id + " not found!")); + .orElseThrow(() -> new ResourceNotFoundException("Course id " + id + " not found!")); courserepos.deleteById(id); } @@ -79,7 +79,7 @@ public Course save(Course course) if (course.getCourseid() != 0) { Course oldCourse = courserepos.findById(course.getCourseid()) - .orElseThrow(() -> new EntityNotFoundException("Course id " + course.getCourseid() + " not found!")); + .orElseThrow(() -> new ResourceNotFoundException("Course id " + course.getCourseid() + " not found!")); newCourse.setCourseid(course.getCourseid()); } @@ -87,7 +87,7 @@ public Course save(Course course) newCourse.setCoursename(course.getCoursename()); Instructor newInstructor = instructorrepos.findById(course.getInstructor() .getInstructorid()) - .orElseThrow(() -> new EntityNotFoundException("Instructor id " + course.getInstructor() + .orElseThrow(() -> new ResourceNotFoundException("Instructor id " + course.getInstructor() .getInstructorid() + " not found!")); newCourse.setInstructor(newInstructor); @@ -97,7 +97,7 @@ public Course save(Course course) { Student newStudent = studentrepos.findById(sc.getStudent() .getStudentid()) - .orElseThrow(() -> new EntityNotFoundException("Instructor id " + sc.getStudent() + .orElseThrow(() -> new ResourceNotFoundException("Instructor id " + sc.getStudent() .getStudentid() + " not found!")); newCourse.getStudents() diff --git a/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctions.java b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctions.java new file mode 100644 index 00000000..75f79a22 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctions.java @@ -0,0 +1,9 @@ +package com.lambdaschool.schools.services; + +import com.lambdaschool.schools.models.ValidationError; + +import java.util.List; + +public interface HelperFunctions { + List getValidationErrors(Throwable cause); +} diff --git a/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionsImpl.java b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionsImpl.java new file mode 100644 index 00000000..a6a633af --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionsImpl.java @@ -0,0 +1,47 @@ +package com.lambdaschool.schools.services; + +import com.lambdaschool.schools.models.ValidationError; +import org.hibernate.exception.ConstraintViolationException; +import org.springframework.stereotype.Service; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; + +import java.util.ArrayList; +import java.util.List; + +@Service(value = "helperFunctions") +public class HelperFunctionsImpl implements HelperFunctions{ + @Override + public List getValidationErrors(Throwable cause) { + List validationErrorList = new ArrayList<>(); + + while (cause != null && !(cause instanceof ConstraintViolationException || cause instanceof MethodArgumentNotValidException)) { + cause = cause.getCause(); + } + + if(cause != null ) { + if(cause instanceof ConstraintViolationException) { + ConstraintViolationException ex = (ConstraintViolationException) cause; + System.out.printf("ConstraintViolationException!!!!!!!!!!!" ); + ValidationError newVE = new ValidationError(); + newVE.setMessage(ex.getConstraintName()); + newVE.setFieldName(ex.getMessage()); + + validationErrorList.add(newVE); + } else { + MethodArgumentNotValidException ex = (MethodArgumentNotValidException) cause; + System.out.printf("MethodArgumentNotValidException!!!!!!!!!!!" ); + List fieldErrors = ex.getBindingResult().getFieldErrors(); + for(FieldError fe : fieldErrors) { + ValidationError newVE = new ValidationError(); + newVE.setMessage(fe.getDefaultMessage()); + newVE.setFieldName(fe.getField()); + + validationErrorList.add(newVE); + } + } + } + + return validationErrorList; + } +} diff --git a/schools/src/main/java/com/lambdaschool/schools/services/StudentServiceImpl.java b/schools/src/main/java/com/lambdaschool/schools/services/StudentServiceImpl.java index 1ad495cd..d25860d4 100644 --- a/schools/src/main/java/com/lambdaschool/schools/services/StudentServiceImpl.java +++ b/schools/src/main/java/com/lambdaschool/schools/services/StudentServiceImpl.java @@ -1,5 +1,6 @@ package com.lambdaschool.schools.services; +import com.lambdaschool.schools.exceptions.ResourceNotFoundException; import com.lambdaschool.schools.models.Course; import com.lambdaschool.schools.models.StudCourses; import com.lambdaschool.schools.models.Student; @@ -8,7 +9,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.persistence.EntityNotFoundException; import java.util.ArrayList; import java.util.List; @@ -49,7 +49,7 @@ public List findAll() public Student findStudentById(long id) { return studentrepos.findById(id) - .orElseThrow(() -> new EntityNotFoundException("Student id " + id + " not found!")); + .orElseThrow(() -> new ResourceNotFoundException("Student id " + id + " not found!")); } @Transactional @@ -57,7 +57,7 @@ public Student findStudentById(long id) public void delete(long id) { studentrepos.findById(id) - .orElseThrow(() -> new EntityNotFoundException("Student id " + id + " not found!")); + .orElseThrow(() -> new ResourceNotFoundException("Student id " + id + " not found!")); studentrepos.deleteById(id); } @@ -70,7 +70,7 @@ public Student save(Student student) if (student.getStudentid() != 0) { Student oldStudent = studentrepos.findById(student.getStudentid()) - .orElseThrow(() -> new EntityNotFoundException("Student id " + student.getStudentid() + " not found!")); + .orElseThrow(() -> new ResourceNotFoundException("Student id " + student.getStudentid() + " not found!")); newStudent.setStudentid(student.getStudentid()); } diff --git a/schools/src/main/resources/application.properties b/schools/src/main/resources/application.properties index 9758fe0c..bf30a1d6 100644 --- a/schools/src/main/resources/application.properties +++ b/schools/src/main/resources/application.properties @@ -23,3 +23,9 @@ spring.datasource.initialization-mode=always # spring.jpa.hibernate.ddl-auto=update # since we have our data in SeedData, do not also load it from data.sql # spring.datasource.initialization-mode=never +# Disabling default error/exception formatter +server.error.whitelabel.enabled=false +# +spring.mvc.throw-exception-if-no-handler-found=true +# +spring.resources.add-mappings=false