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());
});
}
}