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..93f072ba --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java @@ -0,0 +1,36 @@ +package com.lambdaschool.schools.exceptions; + +import com.lambdaschool.schools.services.HelperFunction; +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 HelperFunction helperFunction; + + @Override + public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { + Map errors = super.getErrorAttributes(webRequest, includeStackTrace); + + Map newFormat = new LinkedHashMap<>(); + + newFormat.put("title", errors.get("error")); + newFormat.put("status", errors.get("status")); + newFormat.put("detail", errors.get("message")); + newFormat.put("timestamp", new Date()); + newFormat.put("developerMessage","path " + errors.get("path")); + + newFormat.put("errors", helperFunction.getValiErrors(this.getError(webRequest))); + + return newFormat; + + } +} 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..db98a193 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceNotFoundException.java @@ -0,0 +1,5 @@ +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..476b81c6 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/handlers/RestExceptionHandler.java @@ -0,0 +1,54 @@ +package com.lambdaschool.schools.handlers; + +import com.lambdaschool.schools.exceptions.ResourceNotFoundException; +import com.lambdaschool.schools.models.ErrorDetail; +import com.lambdaschool.schools.services.HelperFunction; +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.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +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 HelperFunction helperFunction; + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFoundException(ResourceNotFoundException rnfe){ + ErrorDetail errorDetail = new ErrorDetail(); + + errorDetail.getTimestamp(new Date()); + errorDetail.setTitle("Resource Not Found"); + errorDetail.setStatus(HttpStatus.NOT_FOUND.value()); + errorDetail.setDetail(rnfe.getMessage()); + errorDetail.setDeveloperMessage(rnfe.getClass().getName()); + errorDetail.setErrors(helperFunction.getValiErrors(rnfe)); + + return new ResponseEntity<>(errorDetail, null, HttpStatus.NOT_FOUND); + + } + + @Override + protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { + ErrorDetail errorDetail = new ErrorDetail(); + + errorDetail.getTimestamp(new Date()); + errorDetail.setTitle("Rest Internal Exception"); + errorDetail.setStatus(status.value()); + errorDetail.setDetail(ex.getMessage()); + errorDetail.setDeveloperMessage(ex.getClass().getName()); + errorDetail.setErrors(helperFunction.getValiErrors(ex)); + + return new ResponseEntity<>(errorDetail, null, status ); + } +} 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..8b9c32be --- /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(Date date) { + 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..f1ae87c8 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/models/ValidationError.java @@ -0,0 +1,32 @@ +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..7dc77964 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,7 @@ 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 +59,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 +67,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 +80,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 +88,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 +98,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/HelperFunction.java b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunction.java new file mode 100644 index 00000000..ac7ff7fc --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunction.java @@ -0,0 +1,11 @@ +package com.lambdaschool.schools.services; + + +import com.lambdaschool.schools.models.ValidationError; + +import java.util.List; + +public interface HelperFunction { + + List getValiErrors(Throwable cause); +} diff --git a/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionImpl.java b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionImpl.java new file mode 100644 index 00000000..81289410 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionImpl.java @@ -0,0 +1,48 @@ +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 = "helperFunction") +public class HelperFunctionImpl implements HelperFunction{ + + + @Override + public List getValiErrors(Throwable cause) { + List validationErrors = new ArrayList<>(); + + while (cause != null && !(cause instanceof ConstraintViolationException || cause instanceof MethodArgumentNotValidException)){ + cause = cause.getCause(); + + if(cause != null){ + if(cause instanceof ConstraintViolationException){ + ConstraintViolationException newException = (ConstraintViolationException)cause; + + ValidationError newValidationError = new ValidationError(); + newValidationError.setMessage(newException.getConstraintName()); + newValidationError.setFieldname(newException.getMessage()); + + validationErrors.add(newValidationError); + } else{MethodArgumentNotValidException newException = (MethodArgumentNotValidException) cause; + + List fieldErrors = newException.getBindingResult().getFieldErrors(); + for(FieldError f : fieldErrors){ + ValidationError newValidationError = new ValidationError(); + newValidationError.setFieldname(f.getField()); + newValidationError.setMessage(f.getDefaultMessage()); + + validationErrors.add(newValidationError); + } + } + } + } + return validationErrors; + } +} 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..7bbf78c4 100644 --- a/schools/src/main/resources/application.properties +++ b/schools/src/main/resources/application.properties @@ -23,3 +23,11 @@ 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 +# +server.error.whitelabel.enabled=false +# +# Tells spring to throw default exception if no exception handler is found +spring.mvc.throw-exception-if-no-handler-found=true +# +# For swagger2config to work you need this +spring.resources.add-mappings=false