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..3d77685d --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java @@ -0,0 +1,33 @@ +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.LinkedHashMap; +import java.util.Map; + +@Component +public class CustomErrorDetails extends DefaultErrorAttributes { + + @Autowired + HelperFunctions helperFunctions; + + @Override + public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { + Map errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace); + + Map errorDetails = new LinkedHashMap<>(); + errorDetails.put("title", errorAttributes.get("error")); + errorDetails.put("status", errorAttributes.get("status")); + errorDetails.put("detail", "Found an issue with School: " + errorAttributes.get("message")); + errorDetails.put("timestamp", errorAttributes.get("timestamp")); + errorDetails.put("developer", "Path: " + errorAttributes.get("path")); + errorDetails.put("errors", helperFunctions.getConstraintViolation(this.getError(webRequest))); + return errorDetails; + + + } +} 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..e36f357c --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/ResourceFoundException.java @@ -0,0 +1,8 @@ +package com.lambdaschool.schools.exceptions; + +public class ResourceFoundException extends RuntimeException{ + + public ResourceFoundException(String message) { + super(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..7f3607a3 --- /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(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..a0f1cca1 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/handlers/RestExceptionHandler.java @@ -0,0 +1,69 @@ +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.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 + HelperFunctions helperFunctions; + + @Override + protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { + ErrorDetail errorDetail = new ErrorDetail(); + errorDetail.setDetail("Found an issue with School: " + ex.getMessage()); + errorDetail.setErrors(helperFunctions.getConstraintViolation(ex)); + errorDetail.setDeveloper(ex.getClass().getName()); + errorDetail.setStatus(status.value()); + errorDetail.setTimestamp(new Date()); + errorDetail.setTitle("Rest Internal Exception"); + return new ResponseEntity<>(errorDetail, headers, status); + } + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFoundException(ResourceNotFoundException ex) + { + + ErrorDetail errorDetail = new ErrorDetail(); + errorDetail.setDetail("Found an issue with School: " + ex.getMessage()); + errorDetail.setErrors(helperFunctions.getConstraintViolation(ex)); + errorDetail.setDeveloper(ex.getClass().getName()); + errorDetail.setStatus(HttpStatus.NOT_FOUND.value()); + errorDetail.setTimestamp(new Date()); + errorDetail.setTitle("Resource Not Found."); + return new ResponseEntity<>(errorDetail, null, HttpStatus.NOT_FOUND); + + } + + @ExceptionHandler(ResourceFoundException.class) + public ResponseEntity handleResourceFoundException(ResourceFoundException ex) + { + + ErrorDetail errorDetail = new ErrorDetail(); + errorDetail.setDetail("Found an issue with School: " + ex.getMessage()); + errorDetail.setErrors(helperFunctions.getConstraintViolation(ex)); + errorDetail.setDeveloper(ex.getClass().getName()); + errorDetail.setStatus(HttpStatus.BAD_REQUEST.value()); + errorDetail.setTimestamp(new Date()); + errorDetail.setTitle("Unexpected Resource."); + 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..59e4e296 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/models/ErrorDetail.java @@ -0,0 +1,68 @@ +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 developer; + private List errors = new ArrayList<>(); + + 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 getDeveloper() { + return developer; + } + + public void setDeveloper(String developer) { + this.developer = developer; + } + + public List getErrors() { + return errors; + } + + public void setErrors(List errors) { + this.errors = errors; + } + + public ErrorDetail() { + } + + +} 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..53615bd4 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/models/ValidationError.java @@ -0,0 +1,26 @@ +package com.lambdaschool.schools.models; + +public class ValidationError { + + private String code; + private String message; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public ValidationError() { + } +} 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..42d425b4 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctions.java @@ -0,0 +1,11 @@ +package com.lambdaschool.schools.services; + +import com.lambdaschool.schools.models.ValidationError; + +import java.util.List; + +public interface HelperFunctions { + + List getConstraintViolation(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..8b27d2d7 --- /dev/null +++ b/schools/src/main/java/com/lambdaschool/schools/services/HelperFunctionsImpl.java @@ -0,0 +1,58 @@ +package com.lambdaschool.schools.services; + +import com.lambdaschool.schools.models.ValidationError; +import org.springframework.stereotype.Service; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; + +import org.hibernate.exception.ConstraintViolationException; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +@Service(value = "helperFunctions") +public class HelperFunctionsImpl implements HelperFunctions{ + + @Override + public List getConstraintViolation(Throwable cause) { + List listVE = new ArrayList<>(); + + while((cause != null) && !(cause instanceof ConstraintViolationException || cause instanceof MethodArgumentNotValidException)) + { + + cause = cause.getCause(); + + } + + if (cause != null) + { + if(cause instanceof ConstraintViolationException) + { + ValidationError newVE = new ValidationError(); + ConstraintViolationException eX = (ConstraintViolationException) cause; + newVE.setCode(eX.getMessage()); + newVE.setMessage(eX.getConstraintName()); + listVE.add(newVE); + } else + { + + MethodArgumentNotValidException ex = (MethodArgumentNotValidException) cause; + List fieldErrors = ex.getBindingResult().getFieldErrors(); + + for(FieldError fe : fieldErrors) + { + + ValidationError newVE = new ValidationError(); + newVE.setCode(fe.getField()); + newVE.setMessage(fe.getDefaultMessage()); + listVE.add(newVE); + + } + + } + } + + return listVE; + } +} 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..dfabcef6 100644 --- a/schools/src/main/resources/application.properties +++ b/schools/src/main/resources/application.properties @@ -18,6 +18,9 @@ spring.jpa.open-in-view=true # drop n create table again, good for testing spring.jpa.hibernate.ddl-auto=create spring.datasource.initialization-mode=always +server.error.whitelabel.enabled=false +spring.mvc.throw-exception-if-no-handler-found=true +spring.resources.add-mappings=false # # Good for production! # spring.jpa.hibernate.ddl-auto=update