flak-jackson converts handler arguments and return values from and to JSON
with Jackson. It is a
plugin: adding the dependency is enough.
implementation "com.github.pcdv.flak:flak-jackson:3.2.1"@JSON on a handler
converts what it returns to JSON, with Content-Type: application/json. A
parameter of an object type is parsed from the JSON body of the request:
@Route("/api/items/:id")
@Put
@JSON
public Item update(String id, Item item) {
return store.save(id, item);
}-
Its type tells Jackson what to build, which can be a class of your own, a
Map, aList, aJsonNode… Flak builds a reader for that type once, when the handler is scanned. The body can be any parameter: aStringor anintis a path variable, and Flak's own types (Request,Form…) are never taken for a body. -
A handler can read JSON without returning JSON: put
@JSONon the parameter rather than on the method.@Route("/api/items") @Post public String create(@JSON Item item) { return store.add(item); }
-
On a class,
@JSONapplies to all the handlers the class declares, except those annotated themselves, e.g. with another mapper. -
@JSON(inputClass = Item.class)states the type to parse, when it cannot be taken from the parameter. -
A
voidhandler annotated with@JSONreturns the JSON literalnull.
The body is read like any other, so the size limit applies. JSON responses are compressed when compression is allowed.
Since Flak 3.1.0.
flak-jackson also builds the parameters annotated with @QueryParams from
the query string, binding its parameters to the properties of a class as
Jackson binds those of a JSON object:
@Route("/api/items")
@JSON
public List<Item> search(@QueryParams Search search) { ... }See Objects built from the query string.
Since 3.2.0, it builds those annotated with @FormParams from the fields of
a form the same way, see Objects built from a form.
By default, a plain ObjectMapper is used. To change its settings, register
your own as the default:
ObjectMapper mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
JacksonPlugin.get(app).registerMapper("default", mapper);Handlers that need other settings can use a mapper of their own, registered
under another name and selected with @JSON("name"):
JacksonPlugin.get(app).registerMapper("pretty",
new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT));
@Route("/api/debug")
@JSON("pretty")
public Map<String, Object> debug() { ... }Register mappers before scanning the handlers that use them. Each handler
builds its ObjectReader and ObjectWriter once, when it is scanned; these
are immutable, so concurrent requests do not contend for them.
The plugin only saves some boilerplate. The same can be done with an output formatter and an input parser (see Responses and Handler arguments):
app.addOutputFormatter("JSON", new JsonOutputFormatter<>(mapper.writer()));
app.addInputParser("JSON", new JsonInputReader<>(mapper.readerFor(Item.class)));
@Route("/api/items")
@Post
@InputFormat("JSON")
@OutputFormat("JSON")
public Item create(Item item) { ... }