{"id":13458624,"url":"https://github.com/zalando/problem-spring-web","last_synced_at":"2025-05-13T15:11:00.331Z","repository":{"id":36692420,"uuid":"40998919","full_name":"zalando/problem-spring-web","owner":"zalando","description":"A library for handling Problems in Spring Web MVC","archived":false,"fork":false,"pushed_at":"2025-03-18T06:50:18.000Z","size":1517,"stargazers_count":1052,"open_issues_count":47,"forks_count":127,"subscribers_count":50,"default_branch":"main","last_synced_at":"2025-05-03T08:09:54.080Z","etag":null,"topics":["error","exception","java","json","microservice","problem","rfc7807","spring","spring-boot","web"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zalando.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-18T21:41:40.000Z","updated_at":"2025-05-02T21:21:56.000Z","dependencies_parsed_at":"2025-03-31T18:05:46.487Z","dependency_job_id":"1c611705-12a6-4868-b9ea-dbd07f714c55","html_url":"https://github.com/zalando/problem-spring-web","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zalando%2Fproblem-spring-web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zalando%2Fproblem-spring-web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zalando%2Fproblem-spring-web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zalando%2Fproblem-spring-web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zalando","download_url":"https://codeload.github.com/zalando/problem-spring-web/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253969249,"owners_count":21992263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error","exception","java","json","microservice","problem","rfc7807","spring","spring-boot","web"],"created_at":"2024-07-31T09:00:54.615Z","updated_at":"2025-05-13T15:10:55.311Z","avatar_url":"https://github.com/zalando.png","language":"Java","readme":"# Problems for Spring MVC and Spring WebFlux\n\n[![Stability: Sustained](https://masterminds.github.io/stability/sustained.svg)](https://masterminds.github.io/stability/sustained.html)\n![Build Status](https://github.com/zalando/problem-spring-web/workflows/build/badge.svg)\n[![Coverage Status](https://img.shields.io/coveralls/zalando/problem-spring-web/main.svg)](https://coveralls.io/r/zalando/problem-spring-web)\n[![Code Quality](https://img.shields.io/codacy/grade/0236149bf46749b1a582f9fbbde2a4eb/main.svg)](https://www.codacy.com/app/whiskeysierra/problem-spring-web)\n[![Release](https://img.shields.io/github/release/zalando/problem-spring-web.svg)](https://github.com/zalando/problem-spring-web/releases)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/zalando/problem-spring-web/main/LICENSE)\n\n*Problem Spring Web* is a set of libraries that makes it easy to produce\n[`application/problem+json`](https://datatracker.ietf.org/doc/html/rfc9457) responses from a Spring\napplication. It fills a niche, in that it connects the [Problem library](https://github.com/zalando/problem) and either \n[Spring Web MVC's exception handling](https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc#using-controlleradvice-classes)\nor [Spring WebFlux's exception handling](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-ann-controller-exceptions)\nso that they work seamlessly together, while requiring minimal additional developer effort. In doing so, it aims to\nperform a small but repetitive task — once and for all.\n\nThe way this library works is based on what we call *advice traits*. An advice trait is a small, reusable\n`@ExceptionHandler` implemented as a [default method](https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html)\nplaced in a single method interface. Those advice traits can be combined freely and don't require to use a common base\nclass for your [`@ControllerAdvice`](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html).\n\n:mag_right: Please check out [Baeldung: A Guide to the Problem Spring Web Library](https://www.baeldung.com/problem-spring-web) for a detailed introduction!\n\n## Features\n\n- lets you choose traits *à la carte*\n- favors composition over inheritance\n- ~20 useful advice traits built in\n- Spring MVC and Spring WebFlux support\n- Spring Security support\n- customizable processing\n\n## Dependencies\n\n- Java 17\n- Any build tool using Maven Central, or direct download\n- Servlet Container for [problem-spring-web](problem-spring-web) or\n- Reactive, non-blocking runtime for [problem-spring-webflux](problem-spring-webflux)\n- Spring 6 (or Spring Boot 3) users may use version \u003e= [0.28.0](https://github.com/zalando/problem-spring-web/releases/tag/0.28.0)\n- Spring 5 (or Spring Boot 2) users may use version [0.27.0](https://github.com/zalando/problem-spring-web/releases/tag/0.27.0)\n- Spring 4 (or Spring Boot 1.5) users may use version [0.23.0](https://github.com/zalando/problem-spring-web/releases/tag/0.23.0)\n- Spring Security 5 (optional)\n- Failsafe 2.3.3 (optional)\n\n## Installation and Configuration\n\n- [Spring Web MVC](problem-spring-web)\n- [Spring WebFlux](problem-spring-webflux)\n\n## Customization\n\nThe problem handling process provided by `AdviceTrait` is built in a way that allows for customization whenever the\nneed arises. All of the following aspects (and more) can be customized by implementing the appropriate advice trait interface:\n\n| Aspect              | Method(s)                   | Default                                                                                               |\n|---------------------|-----------------------------|-------------------------------------------------------------------------------------------------------|\n| Creation            | `AdviceTrait.create(..)`    |                                                                                                       |\n| Logging             | `AdviceTrait.log(..)`       | 4xx as `WARN`, 5xx as `ERROR` including stack trace                                                   |\n| Content Negotiation | `AdviceTrait.negotiate(..)` | `application/json`, `application/*+json`, `application/problem+json` and `application/x.problem+json` |\n| Fallback            | `AdviceTrait.fallback(..)`  | `application/problem+json`                                                                            |\n| Post-Processing     | `AdviceTrait.process(..)`   | n/a                                                                                                   |\n\nThe following example customizes the `MissingServletRequestParameterAdviceTrait` by adding a `parameter` extension field to the `Problem`:\n\n```java\n@ControllerAdvice\npublic class MissingRequestParameterExceptionHandler implements MissingServletRequestParameterAdviceTrait {\n    @Override\n    public ProblemBuilder prepare(Throwable throwable, StatusType status, URI type) {\n        var exception = (MissingServletRequestParameterException) throwable;\n        return Problem.builder()\n                      .withTitle(status.getReasonPhrase())\n                      .withStatus(status)\n                      .withDetail(exception.getMessage())\n                      .with(\"parameter\", exception.getParameterName());\n    }\n}\n```\n\n## Usage\n\nAssuming there is a controller like this:\n\n```java\n@RestController\n@RequestMapping(\"/products\")\nclass ProductsResource {\n\n    @RequestMapping(method = GET, value = \"/{productId}\", produces = APPLICATION_JSON_VALUE)\n    public Product getProduct(String productId) {\n        // TODO implement\n        return null;\n    }\n\n    @RequestMapping(method = PUT, value = \"/{productId}\", consumes = APPLICATION_JSON_VALUE)\n    public Product updateProduct(String productId, Product product) {\n        // TODO implement\n        throw new UnsupportedOperationException();\n    }\n\n}\n```\n\nThe following HTTP requests will produce the corresponding response respectively:\n\n```http\nGET /products/123 HTTP/1.1\nAccept: application/xml\n```\n\n```http\nHTTP/1.1 406 Not Acceptable\nContent-Type: application/problem+json\n\n{\n  \"title\": \"Not Acceptable\",\n  \"status\": 406,\n  \"detail\": \"Could not find acceptable representation\"\n}\n```\n\n```http\nPOST /products/123 HTTP/1.1\nContent-Type: application/json\n\n{}\n```\n\n```http\nHTTP/1.1 405 Method Not Allowed\nAllow: GET\nContent-Type: application/problem+json\n\n{\n  \"title\": \"Method Not Allowed\",\n  \"status\": 405,\n  \"detail\": \"POST not supported\"\n}\n```\n\n### Stack traces and causal chains\n\n**Before you continue**, please read the section about \n[*Stack traces and causal chains*](https://github.com/zalando/problem#stack-traces-and-causal-chains) \nin [zalando/problem](https://github.com/zalando/problem).\n\nIn case you want to enable stack traces, please configure your `ProblemModule` as follows:\n\n```java\nObjectMapper mapper = new ObjectMapper()\n    .registerModule(new ProblemModule().withStackTraces());\n```\n\nCausal chains of problems are **disabled by default**, but can be overridden if desired:\n\n```java\n@ControllerAdvice\nclass ExceptionHandling implements ProblemHandling {\n\n    @Override\n    public boolean isCausalChainsEnabled() {\n        return true;\n    }\n\n}\n```\n\n**Note** Since you have full access to the application context at that point, you can externalize the\nconfiguration to your `application.yml` and even decide to reuse Spring's `server.error.include-stacktrace` property.\n\nEnabling both features, causal chains and stacktraces, will yield:\n\n```yaml\n{\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Illegal State\",\n  \"stacktrace\": [\n    \"org.example.ExampleRestController.newIllegalState(ExampleRestController.java:96)\",\n    \"org.example.ExampleRestController.nestedThrowable(ExampleRestController.java:91)\"\n  ],\n  \"cause\": {\n    \"title\": \"Internal Server Error\",\n    \"status\": 500,\n    \"detail\": \"Illegal Argument\",\n    \"stacktrace\": [\n      \"org.example.ExampleRestController.newIllegalArgument(ExampleRestController.java:100)\",\n      \"org.example.ExampleRestController.nestedThrowable(ExampleRestController.java:88)\"\n    ],\n    \"cause\": {\n      \"title\": \"Internal Server Error\",\n      \"status\": 500,\n      \"detail\": \"Null Pointer\",\n      \"stacktrace\": [\n        \"org.example.ExampleRestController.newNullPointer(ExampleRestController.java:104)\",\n        \"org.example.ExampleRestController.nestedThrowable(ExampleRestController.java:86)\",\n        \"sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\",\n        \"sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\",\n        \"sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\",\n        \"java.lang.reflect.Method.invoke(Method.java:483)\",\n        \"org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\",\n        \"org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\",\n        \"org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\",\n        \"org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\",\n        \"org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)\",\n        \"org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)\",\n        \"org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)\",\n        \"org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)\",\n        \"org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)\",\n        \"org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)\",\n        \"org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)\",\n        \"org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)\",\n        \"org.junit.runners.ParentRunner.run(ParentRunner.java:363)\",\n        \"org.junit.runner.JUnitCore.run(JUnitCore.java:137)\",\n        \"com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)\",\n        \"com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)\",\n        \"com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)\"\n      ]\n    }\n  }\n}\n```\n\n## Known Issues\n\nSpring allows to restrict the scope of a `@ControllerAdvice` to a certain subset of controllers:\n\n```java\n\n@ControllerAdvice(assignableTypes = ExampleController.class)\npublic final class ExceptionHandling implements ProblemHandling\n```\n\nBy doing this you'll loose the capability to handle certain types of exceptions namely:\n- `HttpRequestMethodNotSupportedException`\n- `HttpMediaTypeNotAcceptableException`\n- `HttpMediaTypeNotSupportedException`\n- `NoHandlerFoundException`\n\nWe inherit this restriction from Spring and therefore recommend to use an unrestricted `@ControllerAdvice`.\n\n## Getting Help\n\nIf you have questions, concerns, bug reports, etc., please file an issue in this repository's [Issue Tracker](../../issues).\n\n## Getting Involved/Contributing\n\nTo contribute, simply make a pull request and add a brief description (1-2 sentences) of your addition or change. For\nmore details, check the [contribution guidelines](.github/CONTRIBUTING.md).\n\n## Credits and references\n\n- [Baeldung: A Guide to the Problem Spring Web Library](https://www.baeldung.com/problem-spring-web)\n- [Problem Details for HTTP APIs](http://tools.ietf.org/html/rfc7807)\n- [Problem library](https://github.com/zalando/problem)\n- [Exception Handling in Spring MVC](https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc#using-controlleradvice-classes)\n","funding_links":[],"categories":["Java","REST错误处理","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzalando%2Fproblem-spring-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzalando%2Fproblem-spring-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzalando%2Fproblem-spring-web/lists"}