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 集成添加了一个 Renderer 用于将对象渲染为 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 集成添加了一个 Parser 用于将 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 模块 添加了对 JDK8 类型(如 Optional)的支持。
要使用此类模块,只需将适当配置的 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());
});
}
}