flash-ext-jackson and flash-ext-validation become three modules: - flash-ext-jackson-core: the Codec (one mapper, body/write/writeView), JacksonHandler, the outbound marshalling, and the constraint engine that used to be flash-ext-validation - flash-ext-jackson-json: Json, JsonExtension, JsonHandler - flash-ext-jackson-xml: Xml, XmlExtension, XmlHandler Every Jackson format is the same databind model behind a different factory, so the annotations, the constraints and the published schema are the same for all of them: only the mapper and the content type differ, and that is all a format module says. A route picks its format by the handler it extends — there is no negotiation and nothing to configure. A typed body is now always verified against its own type's jakarta constraints, whatever the format: malformed is a 400, a broken constraint is a 422, and neither reaches the handler. The validator was already allocation-free and stays so; validating is no longer something an application remembers to do. bodyFrom is gone. body has the streaming semantics, because the request's stream is reused per connection while bytes() allocates the whole body: one name, the path that does not allocate. JacksonExtension is JsonExtension, and autoJson() is auto(). The root POM now manages every module of this build, so anything composing Flash imports it once and never names a version again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
61 lines
1.7 KiB
Markdown
61 lines
1.7 KiB
Markdown
# flash-ext-jackson-json
|
|
|
|
JSON bodies and JSON responses.
|
|
|
|
## Install
|
|
|
|
```java
|
|
JsonExtension json = new JsonExtension();
|
|
|
|
FlashApp.create(8080)
|
|
.install(json)
|
|
.use(json.auto())
|
|
.scan("com.acme.handlers")
|
|
.startAndBlock();
|
|
```
|
|
|
|
The default mapper discovers the modules on the classpath (Java Time among them) and writes dates
|
|
as ISO strings; `new JsonExtension(mapper)` takes one of your own. `auto()` serializes whatever a
|
|
handler returns, leaving alone what is already a response: `null`, a `Response`, a `byte[]` or a
|
|
`CharSequence`.
|
|
|
|
## A handler with a body
|
|
|
|
The body type is the handler's type argument, and that is the whole declaration — it is also what
|
|
the OpenAPI document describes and what the constraints are read from:
|
|
|
|
```java
|
|
@POST("/users")
|
|
public final class CreateUser extends JsonHandler<NewUser> {
|
|
@Inject private UserService users;
|
|
|
|
@Override protected Object handle(Request req, Response res, NewUser body) {
|
|
return users.create(body);
|
|
}
|
|
}
|
|
```
|
|
|
|
A malformed body never reaches it (400), nor does one that breaks a constraint (422).
|
|
|
|
## A handler that reads it itself
|
|
|
|
```java
|
|
public final class Import extends RequestHandler {
|
|
@Inject private Json json;
|
|
|
|
@Override public Object handle(Request req, Response res) throws Exception {
|
|
return archive.store(json.body(req, Manifest.class));
|
|
}
|
|
}
|
|
```
|
|
|
|
`Json` is the [`Codec`](../flash-ext-jackson-core) for `application/json`: `body`, `write`,
|
|
`writeView`, `mapper`.
|
|
|
|
## Notes
|
|
|
|
- One mapper per application (or per scope), shared by every handler; `ObjectMapper` is
|
|
thread-safe once configured.
|
|
- Install `flash-ext-jackson-xml` beside this one when an application speaks both: a route picks
|
|
its format by the handler it extends, not by negotiation.
|