Skip to content

Latest commit

 

History

History
114 lines (88 loc) · 3.64 KB

File metadata and controls

114 lines (88 loc) · 3.64 KB

JSON

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

@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, a List, a JsonNode… Flak builds a reader for that type once, when the handler is scanned. The body can be any parameter: a String or an int is 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 @JSON on the parameter rather than on the method.

    @Route("/api/items")
    @Post
    public String create(@JSON Item item) {
      return store.add(item);
    }
  • On a class, @JSON applies 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 void handler annotated with @JSON returns the JSON literal null.

The body is read like any other, so the size limit applies. JSON responses are compressed when compression is allowed.

Objects built from the query string

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.

Configuring Jackson

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.

Without the plugin

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) { ... }