quarkus create app org.acme:rest-json-quickstart \
--extension='resteasy-reactive-jackson' \
--no-code
cd rest-json-quickstart
创建Grade项目,请添加
--gradle
或者
--gradle-kotlin-dsl
参数。
For more information about how to install and use the Quarkus CLI, see the
Quarkus CLI
guide.
mvn io.quarkus.platform:quarkus-maven-plugin:3.6.4:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=rest-json-quickstart \
-Dextensions='resteasy-reactive-jackson' \
-DnoCode
cd rest-json-quickstart
创建Grade项目,请添加
-DbuildTool=gradle
或者
-DbuildTool=gradle-kotlin-dsl
参数。
This command generates a new project importing the RESTEasy Reactive/Jakarta REST and
Jackson
extensions,
and in particular adds the following dependency:
pom.xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-resteasy-reactive-jackson")
quarkus create app org.acme:rest-json-quickstart \
--extension='resteasy-reactive-jsonb' \
--no-code
cd rest-json-quickstart
创建Grade项目,请添加
--gradle
或者
--gradle-kotlin-dsl
参数。
For more information about how to install and use the Quarkus CLI, see the
Quarkus CLI
guide.
mvn io.quarkus.platform:quarkus-maven-plugin:3.6.4:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=rest-json-quickstart \
-Dextensions='resteasy-reactive-jsonb' \
-DnoCode
cd rest-json-quickstart
创建Grade项目,请添加
-DbuildTool=gradle
或者
-DbuildTool=gradle-kotlin-dsl
参数。
This command generates a new project importing the RESTEasy Reactive/Jakarta REST and
JSON-B
extensions,
and in particular adds the following dependency:
pom.xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jsonb</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-resteasy-reactive-jsonb")
public Fruit(String name, String description) {
this.name = name;
this.description = description;
这是非常的简单。需要注意的重要一点是, JSON 序列化层需要具有默认构造函数。
现在,创建
org.acme.rest.json.FruitResource
类,如下所示。
package org.acme.rest.json;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
@Path("/fruits")
public class FruitResource {
private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));
public FruitResource() {
fruits.add(new Fruit("Apple", "Winter fruit"));
fruits.add(new Fruit("Pineapple", "Tropical fruit"));
public Set<Fruit> list() {
return fruits;
@POST
public Set<Fruit> add(Fruit fruit) {
fruits.add(fruit);
return fruits;
@DELETE
public Set<Fruit> delete(Fruit fruit) {
fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
return fruits;
The implementation is pretty straightforward, and you just need to define your endpoints using the Jakarta REST annotations.
Fruit
对象将被 JSON-B 或 Jackson 自动序列化/反序列化,这取决于你在初始化项目时选择的扩展。
在Quarkus中,通过CDI获得的默认Jackson ObjectMapper
(并由Quarkus扩展使用)被配置为忽略未知属性(通过禁用 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
功能)。
You can restore the default behavior of Jackson by setting quarkus.jackson.fail-on-unknown-properties=true
in your application.properties
or on a per-class basis via @JsonIgnoreProperties(ignoreUnknown = false)
.
此外, ObjectMapper
被配置为ISO-8601的日期和时间格式(通过禁用 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
功能)。
Jackson的默认行为可以通过在你的 application.properties
中设置 quarkus.jackson.write-dates-as-timestamps=true
来设置。如果你想改变单个字段的默认行为,你可以使用 @JsonFormat
注解。
另外,Quarkus使得通过CDI beans来配置各种Jackson设置变得非常容易。最简单的(也是建议的)方法是定义一个类型为 io.quarkus.jackson.ObjectMapperCustomizer
的CDI Bean,在其中可以使用任何Jackson配置。
需要注册自定义模块的示例如下所示:
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
@Singleton
public class RegisterCustomModuleCustomizer implements ObjectMapperCustomizer {
public void customize(ObjectMapper mapper) {
mapper.registerModule(new CustomModule());
如果用户选择的话,他们甚至可以提供自己的 ObjectMapper
bean。如果这样做,在产生 ObjectMapper
的CDI生产者中,手动注入和应用所有 io.quarkus.jackson.ObjectMapperCustomizer
Bean是非常重要的。如果不这样做,就会阻止各种扩展所提供的Jackson特定的自定义功能被应用。
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.arc.All;
import io.quarkus.jackson.ObjectMapperCustomizer;
import java.util.List;
import jakarta.inject.Singleton;
public class CustomObjectMapper {
// Replaces the CDI producer for ObjectMapper built into Quarkus
@Singleton
@Produces
ObjectMapper objectMapper(@All List<ObjectMapperCustomizer> customizers) {
ObjectMapper mapper = myObjectMapper(); // Custom `ObjectMapper`
// Apply all ObjectMapperCustomizer beans (incl. Quarkus)
for (ObjectMapperCustomizer customizer : customizers) {
customizer.customize(mapper);
return mapper;
Quarkus automates the registration of Jackson’s Mixin support, via the io.quarkus.jackson.JacksonMixin
annotation.
This annotation can be placed on classes that are meant to be used as Jackson mixins while the classes they are meant to customize
are defined as the value of the annotation.
import io.quarkus.jsonb.JsonbConfigCustomizer;
import jakarta.inject.Singleton;
import jakarta.json.bind.JsonbConfig;
import jakarta.json.bind.serializer.JsonbSerializer;
@Singleton
public class FooSerializerRegistrationCustomizer implements JsonbConfigCustomizer {
public void customize(JsonbConfig config) {
config.withSerializers(new FooSerializer());
A more advanced option would be to directly provide a bean of jakarta.json.bind.JsonbConfig
(with a Dependent
scope) or in the extreme case to provide a bean of type jakarta.json.bind.Jsonb
(with a Singleton
scope).
If the latter approach is leveraged it is very important to manually inject and apply all io.quarkus.jsonb.JsonbConfigCustomizer
beans in the CDI producer that produces jakarta.json.bind.Jsonb
.
Failure to do so will prevent JSON-B specific customizations provided by various extensions from being applied.
import io.quarkus.jsonb.JsonbConfigCustomizer;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Instance;
import jakarta.json.bind.JsonbConfig;
public class CustomJsonbConfig {
// Replaces the CDI producer for JsonbConfig built into Quarkus
@Dependent
JsonbConfig jsonConfig(Instance<JsonbConfigCustomizer> customizers) {
JsonbConfig config = myJsonbConfig(); // Custom `JsonbConfig`
// Apply all JsonbConfigCustomizer beans (incl. Quarkus)
for (JsonbConfigCustomizer customizer : customizers) {
customizer.customize(config);
return config;
Now let’s add a simple web page to interact with our FruitResource
.
Quarkus automatically serves static resources located under the META-INF/resources
directory.
In the src/main/resources/META-INF/resources
directory, add a fruits.html
file with the content from this fruits.html file in it.
现在你可以与你的REST服务进行交互:
当使用GraalVM的本地可执行文件时,需要注册所有将与反射一起使用的类。好消息是,Quarkus在大多数时候都会为你做这项工作。到目前为止,我们还没有注册任何类,甚至没有注册 Fruit
,并且一切正常。
当Quarkus能够从REST方法中推断出序列化的类型时,它会发挥一些作用。当你有以下的REST方法时,Quarkus确定 Fruit
将被序列化:
public List<Fruit> list() {
// ...
Quarkus通过在构建时分析REST方法自动为你执行此操,这就是为什么我们在本指南的第一部分不需要任何反射注册。
Another common pattern in the Jakarta REST world is to use the Response
object.
Response
comes with some nice perks:
public Legume(String name, String description) {
this.name = name;
this.description = description;
现在让我们创建一个 LegumeResource
REST服务,它只有一个返回legumes类列表的方法。
该方法返回一个 Response
,而不是一个 Legume
列表。
package org.acme.rest.json;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
@Path("/legumes")
public class LegumeResource {
private Set<Legume> legumes = Collections.synchronizedSet(new LinkedHashSet<>());
public LegumeResource() {
legumes.add(new Legume("Carrot", "Root vegetable, usually orange"));
legumes.add(new Legume("Zucchini", "Summer squash"));
public Response list() {
return Response.ok(legumes).build();
现在让我们添加一个简单的网页来显示我们的legumes列表。在 src/main/resources/META-INF/resources
目录中,添加一个 legumes.html
文件,其中包含这个https://github.com/quarkusio/quarkus-quickstarts/blob/main/rest-json-quickstart/src/main/resources/META-INF/resources/legumes.html[legumes.html] 文件的内容。
Open a browser to http://localhost:8080/legumes.html, and you will see our list of legumes.
有趣的部分是在将应用程序作为本机可执行文件运行时开始的:
As mentioned above, the issue is that Quarkus was not able to determine the Legume
class will require some reflection by analyzing the REST endpoints.
The JSON serialization library tries to get the list of fields of Legume
and gets an empty list, so it does not serialize the fields' data.