Skip to content

malczuuu/problem4j-spring-web

Repository files navigation

Problem4J Spring Web

Build Status Sonatype License

Part of problem4j package of libraries.

Spring Web integration module for problem4j-core. library that integrates the RFC Problem Details model with exception handling in Spring Boot.

The desired usage of this library is to make all your custom exceptions extend ProblemException from problem4j-core. It's still possible to create custom @RestControllerAdvice-s, but some nuances with @Order are necessary (explained in Usage chapter, which covers also how response bodies for build-in Spring exceptions are overwritten).

Table of Contents

Features

  • ✅ Automatic mapping of exceptions to responses with Problem objects compliant with RFC 7807.
  • ✅ Mapping of exceptions extending ProblemException to responses with Problem objects.
  • ✅ Fallback mapping of Exception to Problem objects representing 500 Internal Server Error.
  • ✅ Simple configuration thanks to Spring Boot autoconfiguration.

Example

import io.github.malczuuu.problem4j.core.Problem;
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.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;

@Order(Ordered.LOWEST_PRECEDENCE - 20)
@Component
@RestControllerAdvice
public class ExampleExceptionAdvice {

  @ExceptionHandler(ExampleException.class)
  public ResponseEntity<Problem> method(ExampleException ex, WebRequest request) {
    Problem problem =
        Problem.builder()
            .type("http://example.com/errors/example-error")
            .title("Example Title")
            .status(400)
            .detail(ex.getMessage())
            .instance("https://example.com/instances/example-instance")
            .build();

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_PROBLEM_JSON);

    HttpStatus status = HttpStatus.valueOf(problem.getStatus());

    return new ResponseEntity<>(problem, headers, status);
  }
}

Usage

Add library as dependency to Maven or Gradle. See the actual versions on Maven Central. Add it along with repository in your dependency manager. Java 17 or higher is required to use this library.

Tested with Spring Boot 3+, but mostly on 3.5.x. However, the idea for this library was to be backwards compatible down to 3.0.0.

Note that spring-webmvc and jackson-databind dependencies must be included alongside problem4j-spring-web, as the number of transitive dependencies was limited.

  1. Maven:
    <dependencies>
        <dependency>
            <groupId>io.github.malczuuu.problem4j</groupId>
            <artifactId>problem4j-spring-web</artifactId>
            <version>${problem4j-spring-web.version}</version>
        </dependency>
    </dependencies>
  2. Gradle (Groovy or Kotlin DSL):
    dependencies {
        implementation("io.github.malczuuu.problem4j:problem4j-spring-web:${problem4j-spring-web.version}")
    }

Overriding of build-in exceptions is performed by custom ExceptionMapping and its implementations. These mappings are instantiated in ExceptionMappingConfiguration with @ConditionalOnClass, per appropriate exception. Therefore, if using this library with previous versions, mappings for exception classes that are not present in classpath are silently ignored.

Do not use mentioned ExceptionMapping in applications, for creating error handler for exceptions other than ProblemException stick to Spring's @RestControllerAdvice, as described in next paragraph.

While creating your own @RestControllerAdvice, make sure to position it with right @Order. In order for your custom implementation to work seamlessly, make sure to position it on at least Ordered.LOWEST_PRECEDENCE - 1 (the lower the value, the higher the priority), as ExceptionAdvice covers the most generic Exception class.

@RestControllerAdvice covered exceptions @Order(...)
ProblemEnhancedExceptionHandler Spring's internal exceptions Ordered.LOWEST_PRECEDENCE - 10
ProblemExceptionAdvice ProblemException Ordered.LOWEST_PRECEDENCE - 10
ConstraintViolationExceptionAdvice ConstraintViolationException Ordered.LOWEST_PRECEDENCE - 10
ExceptionAdvice Exception Ordered.LOWEST_PRECEDENCE

Configuration

Library can be configured with following properties.

problem4j.detail-format

Property that specifies how exception handling imported with this module should print "defail" field of Problem model (lowercase, capitalized - default, uppercase). Useful for keeping the same style of errors coming from library and your application.

Problem4J Links

  • problem4j - Documentation repository.
  • problem4j-core - Core library defining Problem model and ProblemException.
  • problem4j-jackson - Jackson module for serializing and deserializing Problem objects.
  • problem4j-spring-web - Spring Web module extending ResponseEntityExceptionHandler for handling exceptions and returning Problem responses.

About

Spring module for library implementing RFC7807

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •