https://github.com/problem4j/problem4j-core
Core library implementing Problem model according to RFC7807 (aka RFC9457)
https://github.com/problem4j/problem4j-core
java-library problem-details problem-details-for-http-apis rfc7807
Last synced: 3 months ago
JSON representation
Core library implementing Problem model according to RFC7807 (aka RFC9457)
- Host: GitHub
- URL: https://github.com/problem4j/problem4j-core
- Owner: problem4j
- License: mit
- Created: 2023-04-22T22:46:09.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2026-03-01T13:42:43.000Z (4 months ago)
- Last Synced: 2026-03-01T16:54:21.889Z (4 months ago)
- Topics: java-library, problem-details, problem-details-for-http-apis, rfc7807
- Language: Java
- Homepage: https://problem4j.github.io
- Size: 560 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
Awesome Lists containing this project
README
# Problem4J Core
[](https://github.com/problem4j/problem4j-core/actions/workflows/gradle-build.yml)
[][maven-central]
[](https://github.com/problem4j/problem4j-core/blob/main/LICENSE)
This library provides a minimal, framework-agnostic Java model of the [RFC 7807][rfc7807] "Problem Details" object, with
an immutable `Problem` class and a fluent `ProblemBuilder` for convenient construction.
> Note that [RFC 7807][rfc7807] was later extended in [RFC 9457][rfc9457], however core concepts remain the same.
It is intended to be used as a **foundation** for other libraries or applications that add framework-specific behavior
(e.g. Jackson, Spring - see [Problem4J Links](#problem4j-links) chapter).
## Table of Contents
- [Features](#features)
- [Example](#example)
- [Usage](#usage)
- [Project Status](#project-status)
- [Problem4J Links](#problem4j-links)
- [Building from source](#building-from-source)
## Features
- ✅ Immutable `Problem` data model.
- ✅ Dedicated unchecked `ProblemException` to be used in error handling.
- ✅ Builder pattern for fluent construction.
- ✅ Static `Problem.of(...)` factory methods for in-place creation convenience (since `v1.4.0`).
- ✅ `@ProblemMapping` annotation and `ProblemMapper` to allow declarative approach in converting exception instances
into `Problem` objects.
- ✅ Serializable and easy to log or format.
- ✅ HTTP-agnostic (no external dependencies).
- ✅ Follows [RFC 7807][rfc7807] semantics:
- `type` (URI),
- `title` (short summary),
- `status` (numeric code),
- `detail` (detailed description),
- `instance` (URI to the specific occurrence),
- custom field extensions.
- ✅ Integrated with JSpecify annotations for nullability and Kotlin interop (since `v1.4.0`).
- ✅ Supports Java version 8+, but due to producing multi-release JAR, can support **Java Platform Module System** if
using Java version 9+ (since `v1.4.0`).
## Example
Throw an instance of `ProblemException`.
```java
import io.github.problem4j.core.Problem;
import io.github.problem4j.core.ProblemException;
// using fully-fledged builder
Problem problem =
Problem.builder()
.type("https://example.com/errors/invalid-request")
.title("Invalid Request")
.status(400)
.detail("not a valid json")
.instance("https://example.com/instances/1234")
.build();
throw new ProblemException(problem);
// using convenience factory method
throw new ProblemException(Problem.of("Invalid Request", 400, "not a valid json"));
```
Throw an exception annotated with `@ProblemMapping`.
```java
import io.github.problem4j.core.ProblemMapping;
import io.github.problem4j.core.ProblemMapper;
@ProblemMapping(
type = "https://example.org/test/problem",
title = "Test problem",
status = 400,
detail = "failed: {message}",
extensions = {"subject"})
public class MessageException extends RuntimeException {
private final String subject;
public MessageException(String subject, String message) {
super(message);
this.subject = subject;
}
}
MessageException ex = new MessageException("sub", "boom");
ProblemMapper mapper = ProblemMapper.create();
Problem problem = mapper.toProblemBuilder(ex).build();
```
If using Java module system, add the following `requires` directive to your `module-info.java` file.
```java
module org.example.project {
requires io.github.problem4j.core;
}
```
## Usage
Add library as dependency to Maven or Gradle. See the actual versions on [Maven Central][maven-central]. **Java 8** or
higher is required to use this library.
[][maven-central]
1. Maven:
```xml
io.github.problem4j
problem4j-core
{version}
```
2. Gradle (Groovy or Kotlin DSL):
```groovy
dependencies {
implementation("io.github.problem4j:problem4j-core:{version}")
}
```
## Project Status
[](#project-status)
**Problem4J Core** is considered *feature complete*. Only **bug fixes** will be added. New features may be included only
if there is a strong justification for them; otherwise, future projects are expected to build on this one as a
dependency.
## Problem4J Links
- [`problem4j.github.io`](https://problem4j.github.io) - Full documentation of all projects from Problem4J family.
- [`problem4j-core`][problem4j-core] - Core library defining `Problem` model and `ProblemException`.
- [`problem4j-jackson`][problem4j-jackson] - Jackson module for serializing and deserializing `Problem` objects.
- [`problem4j-spring`][problem4j-spring] - Spring modules extending `ResponseEntityExceptionHandler` for handling
exceptions and returning `Problem` responses.
## Building from source
Expand...
Gradle **9.x+** requires **Java 17** or higher to run. For building the project, Gradle automatically picks up **Java
25** via **toolchains** and the `foojay-resolver-convention` plugin. This Java version is needed because the project
uses **ErrorProne** and **NullAway** for static nullness analysis.
The produced artifacts are compatible with **Java 8** thanks to `options.release = 8` in the Gradle `JavaCompile` task.
This means that regardless of the Java version used to run Gradle, the resulting bytecode remains compatible.
The **default Gradle tasks** include `spotlessApply` (for code formatting) and `build` (for compilation and tests).The
simplest way to build the project is to run:
```bash
./gradlew
```
---
To **execute tests** use `test` task. Tests do not change `options.release` so newer Java API can be used.
```bash
./gradlew test
```
---
To **format the code** according to the style defined in [`build.gradle.kts`](./build.gradle.kts) rules use `spotlessApply`
task. **Note** that **building will fail** if code is not properly formatted.
```bash
./gradlew spotlessApply
```
**Note** that if the year has changed, add `-Pspotless.license-year-enabled` flag to update the year in license headers.
The [publishing GitHub Action](.github/workflows/gradle-publish-release.yml) will fail if the year is not updated, but
for local development and builds you can choose to skip it and update the year later.
```bash
./gradlew spotlessApply -Pspotless.license-year-enabled
```
---
To **publish** the built artifacts to **local Maven repository**, use `publishToMavenLocal` task.
```bash
./gradlew publishToMavenLocal
```
Note that for using Maven Local artifacts in target projects, you need to add `mavenLocal()` repository.
```kotlin
repositories {
mavenLocal()
mavenCentral()
}
```
[maven-central]: https://central.sonatype.com/artifact/io.github.problem4j/problem4j-core
[problem4j-core]: https://github.com/problem4j/problem4j-core
[problem4j-jackson]: https://github.com/problem4j/problem4j-jackson
[problem4j-spring]: https://github.com/problem4j/problem4j-spring
[rfc7807]: https://datatracker.ietf.org/doc/html/rfc7807
[rfc9457]: https://datatracker.ietf.org/doc/html/rfc9457