Skip to content

Commit 807ba08

Browse files
committed
Update README.mds and javadocs
1 parent cab3a61 commit 807ba08

File tree

49 files changed

+819
-76
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+819
-76
lines changed

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,7 @@ to resolve to proper HTTP links dynamically.
561561
Property that defines a template for overriding the `"type"` field in `Problem` responses. The value may contain special
562562
placeholders that will be replaced at runtime:
563563

564-
- `{problem.type}` — the original problem’s `"type"` value
565-
- `{context.traceId}` — the current request’s trace identifier (if available)
564+
- `{problem.type}` — the original problem’s `"type"` value.
566565

567566
Defaults to `null` (no override applied). This can be used to unify or enrich problem type URIs across the application.
568567

@@ -574,6 +573,9 @@ Defaults to `null` (no override applied). This can be used to unify or enrich pr
574573
>
575574
> the post processor will change `"type"` value to `"https://errors.example.com/problems/validation`.
576575
576+
This feature will override original type only if resulting `type` will not be empty. Note that the resulting `type` must
577+
be a valid URI.
578+
577579
### `problem4j.instance-override`
578580
579581
This property allow overriding the `"instance"` field of `Problem` responses with custom templates at the environment
@@ -583,8 +585,8 @@ enabling them to resolve to proper HTTP links dynamically.
583585
Property that defines a template for overriding the `"instance"` field in `Problem` responses. The value may contain
584586
special placeholders that will be replaced at runtime:
585587
586-
- `{problem.instance}` — the original problem’s `"instance"` value
587-
- `{context.traceId}` — the current request’s trace identifier (if available)
588+
- `{problem.instance}` — the original problem’s `"instance"` value,
589+
- `{context.traceId}` — the current request’s trace identifier (if available).
588590
589591
Defaults to `null` (no override applied). This is useful for controlling how problem instances are represented in your
590592
API responses, even without tracing enabled.
@@ -599,6 +601,9 @@ API responses, even without tracing enabled.
599601
>
600602
> For using `{problem.instance}` placeholder, the `instance` field will behave similarly to `type-override`.
601603
604+
This feature will override original `instance` only if resulting type will not be empty. Note that the resulting
605+
`instance` must be a valid URI.
606+
602607
### `problem4j.resolver-caching.enabled`
603608
604609
Enables caching of resolved `ProblemResolver` instances to avoid repeated reflection and lookup. Defaults to `false`
@@ -608,7 +613,7 @@ stable set of exception / resolver types.
608613
### `problem4j.resolver-caching.max-cache-size`
609614
610615
Maximum number of resolver entries stored when caching is enabled. Defaults to `128`. Uses LRU (least recently used)
611-
eviction once the limit is exceeded. Values `<= 0` mean the cache is unbounded (no eviction) use cautiously if many
616+
eviction once the limit is exceeded. Values `<= 0` mean the cache is unbounded (no eviction) - use cautiously if many
612617
distinct resolver types may appear.
613618
614619
Example:
@@ -620,7 +625,7 @@ problem4j.resolver-caching.max-cache-size=256
620625
621626
Notes:
622627
623-
- If you rarely introduce new resolver types, a small cache (64256) is usually enough.
628+
- If you rarely introduce new resolver types, a small cache (64-256) is usually enough.
624629
- Leave disabled if startup / reflection cost is negligible or resolver set is highly dynamic.
625630
626631
## FAQ

problem4j-spring-bom/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# BOM of Problem4J
2+
3+
Bill Of Materials (BOM) for the Spring integrations of **Problem4J**, a library implementing *RFC 7807 - Problem Details
4+
for HTTP APIs*.
5+
6+
Importing this BOM lets you declare the individual `problem4j-*` Spring modules **without repeating versions** and keeps
7+
all components aligned.
8+
9+
## Using the BOM
10+
11+
### Gradle (Kotlin DSL)
12+
13+
Add the BOM to `implementation(platform(...))`, then declare modules without versions.
14+
15+
```kotlin
16+
dependencies {
17+
implementation(platform("io.github.malczuuu.problem4j:problem4j-spring-bom:1.0.0-rc2"))
18+
19+
implementation("io.github.malczuuu.problem4j:problem4j-core")
20+
implementation("io.github.malczuuu.problem4j:problem4j-jackson")
21+
implementation("io.github.malczuuu.problem4j:problem4j-spring-web")
22+
implementation("io.github.malczuuu.problem4j:problem4j-spring-webmvc")
23+
implementation("io.github.malczuuu.problem4j:problem4j-spring-webflux")
24+
}
25+
```
26+
27+
### Maven
28+
29+
Add the BOM to `<dependencyManagement>` with `import` scope, then declare modules without versions.
30+
31+
```xml
32+
33+
<dependencyManagement>
34+
<dependencies>
35+
<dependency>
36+
<groupId>io.github.malczuuu.problem4j</groupId>
37+
<artifactId>problem4j-spring-bom</artifactId>
38+
<version>1.0.0-rc2</version>
39+
<type>pom</type>
40+
<scope>import</scope>
41+
</dependency>
42+
</dependencies>
43+
</dependencyManagement>
44+
45+
<dependencies>
46+
<dependency>
47+
<groupId>io.github.malczuuu.problem4j</groupId>
48+
<artifactId>problem4j-core</artifactId>
49+
</dependency>
50+
<dependency>
51+
<groupId>io.github.malczuuu.problem4j</groupId>
52+
<artifactId>problem4j-jackson</artifactId>
53+
</dependency>
54+
<dependency>
55+
<groupId>io.github.malczuuu.problem4j</groupId>
56+
<artifactId>problem4j-spring-web</artifactId>
57+
</dependency>
58+
<dependency>
59+
<groupId>io.github.malczuuu.problem4j</groupId>
60+
<artifactId>problem4j-spring-webmvc</artifactId>
61+
</dependency>
62+
<dependency>
63+
<groupId>io.github.malczuuu.problem4j</groupId>
64+
<artifactId>problem4j-spring-webflux</artifactId>
65+
</dependency>
66+
</dependencies>
67+
```

problem4j-spring-web/src/main/java/io/github/malczuuu/problem4j/spring/web/annotation/DefaultProblemMappingProcessor.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,18 @@ public boolean isMappingCandidate(Throwable t) {
9696
return t != null && t.getClass().isAnnotationPresent(ProblemMapping.class);
9797
}
9898

99+
/** Returns the {@link ProblemMapping} annotation from the class if present, otherwise null. */
99100
private ProblemMapping findAnnotation(Class<?> clazz) {
100101
if (clazz == null) {
101102
return null;
102103
}
103104
return clazz.getAnnotation(ProblemMapping.class);
104105
}
105106

107+
/**
108+
* Applies the "type" value from {@link ProblemMapping#type()} after placeholder interpolation;
109+
* ignores invalid URIs.
110+
*/
106111
private void applyTypeOnBuilder(
107112
ProblemBuilder builder, ProblemMapping mapping, Throwable t, ProblemContext context) {
108113
String rawType = mapping.type() == null ? "" : mapping.type().trim();
@@ -118,6 +123,7 @@ private void applyTypeOnBuilder(
118123
}
119124
}
120125

126+
/** Applies the interpolated title if present and non-empty. */
121127
private void applyTitleOnBuilder(
122128
ProblemBuilder builder, ProblemMapping mapping, Throwable t, ProblemContext context) {
123129
String titleRaw = mapping.title() == null ? "" : mapping.title();
@@ -129,12 +135,14 @@ private void applyTitleOnBuilder(
129135
}
130136
}
131137

138+
/** Sets the HTTP status when greater than zero. */
132139
private void applyStatusOnBuilder(ProblemMapping mapping, ProblemBuilder builder) {
133140
if (mapping.status() > 0) {
134141
builder.status(mapping.status());
135142
}
136143
}
137144

145+
/** Applies the interpolated detail text if non-empty. */
138146
private void applyDetailOnBuilder(
139147
ProblemBuilder builder, ProblemMapping mapping, Throwable t, ProblemContext context) {
140148
String detailRaw = mapping.detail() == null ? "" : mapping.detail();
@@ -146,6 +154,7 @@ private void applyDetailOnBuilder(
146154
}
147155
}
148156

157+
/** Applies the interpolated instance value; ignores invalid URIs. */
149158
private void applyInstanceOnBuilder(
150159
ProblemBuilder builder, ProblemMapping mapping, Throwable t, ProblemContext context) {
151160
String rawInstance = mapping.instance() == null ? "" : mapping.instance().trim();
@@ -161,6 +170,7 @@ private void applyInstanceOnBuilder(
161170
}
162171
}
163172

173+
/** Adds extension fields resolved from {@link ProblemMapping#extensions()}. */
164174
private void applyExtensionsOnBuilder(
165175
ProblemBuilder builder, ProblemMapping mapping, Throwable t) {
166176
String[] extensions = mapping.extensions();
@@ -179,10 +189,15 @@ private void applyExtensionsOnBuilder(
179189
}
180190

181191
/**
182-
* Interpolate placeholders of form {name}. Special forms: - {message} - {context.key} -
183-
* {context.traceId} (shorthand for {context.traceId}) - other names: looks for instance field.
192+
* Interpolates placeholders of the form {@code {name}}. Supported keys:
193+
*
194+
* <ul>
195+
* <li>{@code message} - throwable message
196+
* <li>{@code context.traceId} - trace ID from context
197+
* <li>Any other token - value of a matching field in the throwable class hierarchy
198+
* </ul>
184199
*
185-
* <p>If a placeholder resolves to null - it's replaced by empty string.
200+
* Missing values resolve to an empty string.
186201
*/
187202
private String interpolate(String template, Throwable t, ProblemContext context) {
188203
if (template == null) {
@@ -210,10 +225,7 @@ private String interpolate(String template, Throwable t, ProblemContext context)
210225
return sb.toString();
211226
}
212227

213-
/**
214-
* Resolve a value for a placeholder name from the throwable or context. Checks only instance
215-
* field (including private) and searches up class hierarchy.
216-
*/
228+
/** Resolves a placeholder by reflective field lookup up the throwable class hierarchy. */
217229
private Object resolvePlaceholderSource(Throwable t, String name) {
218230
if (t == null || !StringUtils.hasLength(name)) {
219231
return null;

problem4j-spring-web/src/main/java/io/github/malczuuu/problem4j/spring/web/annotation/ProblemMappingProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* }
2222
* }</pre>
2323
*
24-
* <p>Implementations should return {@code null} if the exception class is not annotated with {@link
24+
* <p>Implementations should return {@code null} if the exception class is not annotated with {@code
2525
* ProblemMapping}, and may throw {@link ProblemProcessingException} if an error occurs during
2626
* problem creation.
2727
*

problem4j-spring-web/src/main/java/io/github/malczuuu/problem4j/spring/web/annotation/ProblemProcessingException.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,48 @@
77
*/
88
public class ProblemProcessingException extends RuntimeException {
99

10+
/** Creates a new exception with no detail message and no cause. */
1011
public ProblemProcessingException() {
1112
super();
1213
}
1314

15+
/**
16+
* Creates a new exception with the specified detail message.
17+
*
18+
* @param message human-readable explanation of the failure
19+
*/
1420
public ProblemProcessingException(String message) {
1521
super(message);
1622
}
1723

24+
/**
25+
* Creates a new exception wrapping the given cause.
26+
*
27+
* @param cause underlying cause (may be {@code null})
28+
*/
1829
public ProblemProcessingException(Throwable cause) {
1930
super(cause);
2031
}
2132

33+
/**
34+
* Creates a new exception with the specified detail message and cause.
35+
*
36+
* @param message human-readable explanation
37+
* @param cause underlying cause (may be {@code null})
38+
*/
2239
public ProblemProcessingException(String message, Throwable cause) {
2340
super(message, cause);
2441
}
2542

43+
/**
44+
* Advanced constructor allowing full control over suppression and stack trace writability.
45+
* Typically used only internally or in tests.
46+
*
47+
* @param message detail message
48+
* @param cause underlying cause (may be {@code null})
49+
* @param enableSuppression whether suppression is enabled or disabled
50+
* @param writableStackTrace whether the stack trace should be writable
51+
*/
2652
protected ProblemProcessingException(
2753
String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
2854
super(message, cause, enableSuppression, writableStackTrace);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
package io.github.malczuuu.problem4j.spring.web.context;
22

3+
/**
4+
* Settings used when building a {@link ProblemContext} for incoming requests.
5+
*
6+
* <p>Provides access to infrastructure configuration such as the HTTP header name that carries a
7+
* trace identifier. Implementations are typically backed by external configuration (e.g. Spring
8+
* Boot properties) and are expected to be thread-safe.
9+
*/
310
public interface ProblemContextSettings {
411

12+
/**
13+
* Returns the name of the HTTP header that contains a trace / correlation ID.
14+
*
15+
* <p>The trace ID (if present) may be injected into generated Problem responses (e.g. via
16+
* placeholders in instance/type override templates) and echoed back to clients to aid in log
17+
* correlation and diagnostics.
18+
*
19+
* @return the tracing header name, or {@code null} if tracing is disabled / not configured
20+
*/
521
String getTracingHeaderName();
622
}

problem4j-spring-web/src/main/java/io/github/malczuuu/problem4j/spring/web/format/IdentityProblemFormat.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
/** Convenience implementation for {@link ProblemFormat} which doesn't transform input data. */
44
public class IdentityProblemFormat implements ProblemFormat {
55

6+
/**
7+
* Returns the input detail unchanged (identity formatting).
8+
*
9+
* @param detail original detail text (may be {@code null})
10+
* @return the same {@code detail} value
11+
*/
612
@Override
713
public String formatDetail(String detail) {
814
return detail;

0 commit comments

Comments
 (0)