@Consumes says what a route reads. It was also deciding what the document said a route answers, through a JSON default nothing could override: a handler that takes a JSON body is not thereby a handler that answers JSON. @Produces now says that, beside @Consumes and as descriptive as it is — on the handler, or once on a base class. Every response takes its media type from it, JSON when nothing declares one, and the error object stays JSON because that is what Flash answers a failure with whatever the route produces. Content loses contentType with it. One handler answers in one format and a status code does not change that, so the media type was in the wrong place; a response with no schema and no return type to infer one from is a response with no body, which is what a 204 was using it to say. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flash-ext-jackson-json
JSON bodies and JSON responses.
Install
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:
@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
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 for application/json: body, write,
writeView, mapper.
Notes
- One mapper per application (or per scope), shared by every handler;
ObjectMapperis thread-safe once configured. - Install
flash-ext-jackson-xmlbeside this one when an application speaks both: a route picks its format by the handler it extends, not by negotiation.