このマニュアルは現在進行形で、不完全です。
改良に協力したい、という場合は(協力していただけると幸いです)、READMEをご覧ください。

16 Jackson

Jackson JSONマーシャリングライブラリとの統合は、JSON を操作する機能を提供します。これはratpack-coreの一部として提供されます。

Ratpack 2.0.0-rc-1の時点で(および依存します)Jackson Core 2.13.1に対して構築されます。

ratpack.core.jackson.JacksonクラスはJackson関連機能のほとんどを提供します。

1.16 JSONレスポンスの書き込み

Jackson統合はオブジェクトをJSONとしてレンダリングするためのレンダラーを追加します。

Jackson.json()メソッドは(Jacksonによってシリアライズ可能な)任意のオブジェクトをラップしてContext.render()メソッドで使用できるようにします。

import ratpack.test.embed.EmbeddedApp;
import ratpack.core.http.client.ReceivedResponse;

import static ratpack.core.jackson.Jackson.json;
import static org.junit.jupiter.api.Assertions.*;

public class Example {

  public static class Person {
    private final String name;
    public Person(String name) {
      this.name = name;
    }
    public String getName() {
      return name;
    }
  }

  public static void main(String... args) throws Exception {
    EmbeddedApp.of(s -> s
      .handlers(chain ->
        chain.get(ctx -> ctx.render(json(new Person("John"))))
      )
    ).test(httpClient -> {
      ReceivedResponse response = httpClient.get();
      assertEquals("{\"name\":\"John\"}", response.getBody().getText());
      assertEquals("application/json", response.getBody().getContentType().getType());
    });
  }
}

ストリーミングやJSONイベントを含む、さらに多くの例についてはJacksonクラスドキュメントを参照してください。

2.16 JSONリクエストの読み込み

Jackson統合はJSONリクエスト本文をオブジェクトに変換するためのパーサーを追加します。

Jackson.jsonNode()Jackson.fromJson()メソッドはContext.parse()メソッドで使用されるオブジェクトを作成するために使用できます。

import ratpack.guice.Guice;
import ratpack.test.embed.EmbeddedApp;
import ratpack.core.http.client.ReceivedResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.reflect.TypeToken;

import java.util.List;

import static ratpack.func.Types.listOf;
import static ratpack.core.jackson.Jackson.jsonNode;
import static ratpack.core.jackson.Jackson.fromJson;
import static org.junit.jupiter.api.Assertions.*;

public class Example {

  public static class Person {
    private final String name;
    public Person(@JsonProperty("name") String name) {
      this.name = name;
    }
    public String getName() {
      return name;
    }
  }

  public static void main(String... args) throws Exception {
    EmbeddedApp.of(s -> s
      .handlers(chain -> chain
        .post("asNode", ctx -> {
          ctx.render(ctx.parse(jsonNode()).map(n -> n.get("name").asText()));
        })
        .post("asPerson", ctx -> {
          ctx.render(ctx.parse(fromJson(Person.class)).map(p -> p.getName()));
        })
        .post("asPersonList", ctx -> {
          ctx.render(ctx.parse(fromJson(listOf(Person.class))).map(p -> p.get(0).getName()));
        })
      )
    ).test(httpClient -> {
      ReceivedResponse response = httpClient.requestSpec(s ->
        s.body(b -> b.type("application/json").text("{\"name\":\"John\"}"))
      ).post("asNode");
      assertEquals("John", response.getBody().getText());

      response = httpClient.requestSpec(s ->
        s.body(b -> b.type("application/json").text("{\"name\":\"John\"}"))
      ).post("asPerson");
      assertEquals("John", response.getBody().getText());

      response = httpClient.requestSpec(s ->
        s.body(b -> b.type("application/json").text("[{\"name\":\"John\"}]"))
      ).post("asPersonList");
      assertEquals("John", response.getBody().getText());
    });
  }
}

統合はno optsパーサーを追加し、これによりContext.parse(Class)Context.parse(TypeToken)メソッドを使用できます。

import ratpack.test.embed.EmbeddedApp;
import ratpack.core.http.client.ReceivedResponse;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.reflect.TypeToken;

import java.util.List;

import static ratpack.func.Types.listOf;
import static org.junit.jupiter.api.Assertions.*;

public class Example {

  public static class Person {
    private final String name;
    public Person(@JsonProperty("name") String name) {
      this.name = name;
    }
    public String getName() {
      return name;
    }
  }

  public static void main(String... args) throws Exception {
    EmbeddedApp.of(s -> s
      .handlers(chain -> chain
        .post("asPerson", ctx -> {
          ctx.parse(Person.class).then(person -> ctx.render(person.getName()));
        })
        .post("asPersonList", ctx -> {
          ctx.parse(listOf(Person.class)).then(person -> ctx.render(person.get(0).getName()));
        })
      )
    ).test(httpClient -> {
      ReceivedResponse response = httpClient.requestSpec(s ->
        s.body(b -> b.type("application/json").text("{\"name\":\"John\"}"))
      ).post("asPerson");
      assertEquals("John", response.getBody().getText());

      response = httpClient.requestSpec(s ->
        s.body(b -> b.type("application/json").text("[{\"name\":\"John\"}]"))
      ).post("asPersonList");
      assertEquals("John", response.getBody().getText());
    });
  }
}

3.16 Jacksonの設定

Jackson APIはObjectMapperに基づいています。Ratpackは自動的にベースレジストリにデフォルトインスタンスを追加します。Jacksonの動作を設定するには、このインスタンスを上書きします。

Jacksonフィーチャモジュールにより、Jacksonは追加のデータ型と機能をサポートするように拡張できます。たとえばJDK8モジュールOptionalなどのJDK8データ型に対するサポートを追加します。

このようなモジュールを使用するには、適切に設定された ObjectMapperを単純にレジストリに追加します。

import ratpack.test.embed.EmbeddedApp;
import ratpack.core.http.client.ReceivedResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;

import java.util.Optional;

import static ratpack.core.jackson.Jackson.json;
import static org.junit.jupiter.api.Assertions.*;

public class Example {

  public static class Person {
    private final String name;
    public Person(String name) {
      this.name = name;
    }
    public String getName() {
      return name;
    }
  }

  public static void main(String... args) throws Exception {
    EmbeddedApp.of(s -> s
      .registryOf(r -> r
        .add(ObjectMapper.class, new ObjectMapper().registerModule(new Jdk8Module())) 
      )
      .handlers(chain ->
        chain.get(ctx -> {
          Optional<Person> personOptional = Optional.of(new Person("John"));
          ctx.render(json(personOptional));
        })
      )
    ).test(httpClient -> {
      ReceivedResponse response = httpClient.get();
      assertEquals("{\"name\":\"John\"}", response.getBody().getText());
      assertEquals("application/json", response.getBody().getContentType().getType());
    });
  }
}