Migrating to Quarkus REST (formerly RESTEasy Reactive)

大多数情况下,从 RESTEasy Classic 迁移到 Quarkus REST(以前称为 RESTEasy Reactive)非常简单,但有少数情况需要引起注意。本文档提供了一个列表,列出迁移尝试者应该注意的问题。

Migrating from RESTEasy Classic to Quarkus REST (formerly RESTEasy Reactive) is straightforward in most cases, however there are a few cases that require some attention. This document provides a list of issues users attempting the migration should be aware of.

Quarkus REST 的参考文档可以在 here 中找到。

The reference documentation of Quarkus REST can be found here.

Server

Quarkus REST 的服务器部分( quarkus-rest 及其依赖项)提供了 Jakarta REST 规范的实现,但利用了 Quarkus 的构建时间处理功能和 Vert.x 提供的统一 I/O 模型。

The server part of Quarkus REST (quarkus-rest and its dependencies) provide an implementation of the Jakarta REST specification, but leverage Quarkus' build time processing and the unified I/O model provided by Vert.x.

Dependencies

下表将旧版 RESTEasy 依赖性与新的 Quarkus REST 依赖性进行匹配。

The following table matches the legacy RESTEasy dependencies with the new Quarkus REST ones.

Legacy Quarkus REST

quarkus-resteasy

quarkus-rest

quarkus-resteasy-jackson

quarkus-rest-jackson

quarkus-resteasy-jsonb

quarkus-rest-jsonb

quarkus-resteasy-jaxb

quarkus-rest-jaxb

quarkus-resteasy-qute

quarkus-rest-qute

quarkus-resteasy-mutiny 没有相应的依赖项,因为 Quarkus REST 提供了开箱即用的 Mutiny 集成。

The quarkus-resteasy-mutiny does not have a corresponding dependency, as Quarkus REST provides Mutiny integration out of the box.

Annotations

Quarkus REST 不支持 org.jboss.resteasy.annotations 包下的各种自定义注释。

Quarkus REST does not support the various custom annotation under the org.jboss.resteasy.annotations package.

下表将旧版 RESTEasy 注释与新的 Quarkus REST 注释进行匹配。

The following table matches the legacy RESTEasy annotations with the new Quarkus REST ones.

Legacy Quarkus REST Comments

org.jboss.resteasy.annotations.jaxrs.PathParam

org.jboss.resteasy.reactive.RestPath

This annotation is not necessary when the path part matches the method parameter name

org.jboss.resteasy.annotations.jaxrs.QueryParam

org.jboss.resteasy.reactive.RestQuery

org.jboss.resteasy.annotations.jaxrs.FormParam

org.jboss.resteasy.reactive.RestForm

org.jboss.resteasy.annotations.jaxrs.HeaderParam

org.jboss.resteasy.reactive.RestHeader

org.jboss.resteasy.annotations.jaxrs.CookieParam

org.jboss.resteasy.reactive.RestCookie

org.jboss.resteasy.annotations.jaxrs.MatrixParam

org.jboss.resteasy.reactive.RestMatrix

org.jboss.resteasy.annotations.cache.Cache

org.jboss.resteasy.reactive.Cache

org.jboss.resteasy.annotations.cache.NoCache

org.jboss.resteasy.reactive.NoCache

org.jboss.resteasy.annotations.SseElementType

org.jboss.resteasy.reactive.RestStreamElementType

org.jboss.resteasy.annotations.Separator

org.jboss.resteasy.reactive.Separator

前一个表不包括 org.jboss.resteasy.annotations.Form 注释,因为没有可替代它的特定于 Quarkus REST 的注释。相反,鼓励用户使用在服务器和客户端上均受支持的 Jakarta REST 标准 jakarta.ws.rs.BeanParam 注释。

The previous table does not include the org.jboss.resteasy.annotations.Form annotation because there is no Quarkus REST specific replacement for it. Users are instead encouraged to use the Jakarta REST standard jakarta.ws.rs.BeanParam annotation which is supported on both the server and the client.

Jakarta REST providers

虽然 Quarkus REST 提供了与 RESTEasy Classic 相同的规范兼容的行为,但它在运行时不包含相同的精确提供程序实现。

Although Quarkus REST provides the same spec compliant behavior as RESTEasy Classic does, it does not include the same exact provider implementations at runtime.

提供程序的差异可能会导致不同行为的最常见情况是包含的`jakarta.ws.rs.ext.ExceptionMapper`实现。要查看应用程序中包含哪些类,请以开发模式启动应用程序,然后导航至[role="bare"][role="bare"]http://localhost:8080/q/dev-ui/io.quarkus.quarkus-rest/exception-mappers。

The most common case where the difference in providers might result in different behavior, is the included jakarta.ws.rs.ext.ExceptionMapper implementations. To see what classes are included in the application, launch the application in dev mode and navigate to [role="bare"]http://localhost:8080/q/dev-ui/io.quarkus.quarkus-rest/exception-mappers.

Service Loading

RESTEasy Classic 支持使用 Java 的服务加载器在构建时确定提供程序。为了确保在构建时确定所有提供程序,Quarkus REST 不支持此功能。相反,建议在应用程序依赖项中具有提供程序的用户使用 CDI 指南的Bean Discovery部分中描述的一种方法对这些依赖项进行索引。

RESTEasy Classic supports determining providers at build time using Java’s Service Loader. In order to ensure that all providers are determined at build time, Quarkus REST does not support this feature. Instead, users that have providers in application dependencies are encouraged to index those dependencies using one of the methods described in the Bean Discovery section of the CDI guide.

Multipart support

Quarkus REST 中的 HTTP 多部分支持*not*不重用与 RESTEasy Classic 相同的类型或注释,因此建议用户阅读参考文档的this部分。

HTTP Multipart support in Quarkus REST does not reuse the same types or annotations as RESTEasy Classic and thus users are encouraged to read this part of the reference documentation.

将多部分资源迁移到 Quarkus REST 的用户应注意配置参数`quarkus.http.limits.max-form-attribute-size`,因为它对每个部分的大小设定了上限。任何部分大小超过此配置值的请求将导致 HTTP 状态代码 413。

Users migrating multipart resources to Quarkus REST should be aware of the configuration parameter quarkus.http.limits.max-form-attribute-size, as this poses an upper limit to the size of each part. Any request with a part size exceeding this configuration value will result in HTTP status code 413.

Default media types

Quarkus 在确定 Jakarta REST 方法的媒体类型时使用智能默认值,以便简化常见的用例。quarkus-rest`和`quarkus-resteasy`之间的区别在于当方法返回`String`时使用`text/plain`作为默认媒体类型而不是`text/html

Quarkus uses smart defaults when determining the media type of Jakarta REST methods in order to simplify common use cases. The difference between quarkus-rest and quarkus-resteasy is the use of text/plain as the default media type instead of text/html when the method returns a String.

Injection of @SessionScoped beans

当前不支持`@SessionScoped`bean。如果你确实需要此功能,则需要使用 RESTEasy Classic 而不是 RESTEasy Reactive。

@SessionScoped beans are currently not supported. Should you really need this functionality, you’ll need to use RESTEasy Classic instead of RESTEasy Reactive.

Servlets

Quarkus REST not 支持 servlet。如果您的项目依赖于 servlet,则必须迁移它们。基于 servlet 的 JAX-RS 实现必须使用 @Context 注释支持这些类型的注入:ServletConfigServletContextHttpServletRequestHttpServletResponse。因为 Quarkus REST 不是基于 servlet 的,所以这些注入将不起作用。

Quarkus REST does not support servlets. If your project depends on servlets you have to migrate them. A servlet-based JAX-RS implementation must support injections of these types with the @Context annotation: ServletConfig, ServletContext, HttpServletRequest and HttpServletResponse. Since Quarkus REST is not servlet-based these injections will not work.

即使你依赖于提供接口的扩展(例如`quarkus-undertow`),也不总是很明显这点会失败。例如,如果你编写此内容,则可以编译它,但在调用它时会得到一个异常:

It is not always obvious that this will fail especially if you depend on an extension like quarkus-undertow which supplies the interfaces. For example, if you write this you could compile it but get an exception on calling it:

@Path("/reactive")
public class ReactiveResource {

    @Context
    HttpServletRequest httpServletRequest;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String servletContextPath() {

        String contextPath = httpServletRequest.getContextPath();

        return "My context path is: " + contextPath;
    }
}

第三方库也是如此。如果它们碰巧依赖于 servlet,则需要找到它们的迁移路径。

The same is true for your third-party libraries. If they happen to depend on servlets you need to find a migration path for them.

Log authentication and authorization failures

Quarkus REST 端点安全检查在调用CDI interceptors之前执行。记录 Quarkus Security 身份验证异常的最安全方法是确保启用了主动身份验证并使用 Vert.x HTTP 路由故障处理程序。有关更多信息,请参阅主动身份验证指南的Customize authentication exception responses部分。

The Quarkus REST endpoint security checks are performed before CDI interceptors are invoked. The safest approach to log Quarkus Security authentication exceptions is to ensure that proactive authentication is enabled and to use Vert.x HTTP route failure handlers. For more information, see the Customize authentication exception responses section of the Proactive authentication guide.

Client

REST 客户端(quarkus-rest-client`及其依赖项)取代了基于 RESTEasy Classic 的旧版`quarkus-resteasy-client,并利用 Quarkus 的构建时间处理和 Vert.x 提供的统一 I/O 模型。

The REST Client (quarkus-rest-client and its dependencies) replaces the legacy RESTEasy Classic-based quarkus-resteasy-client and leverages Quarkus' build time processing and the unified I/O model provided by Vert.x.

Dependencies

下表将旧版基于 RESTEasy Classic 的 REST 客户端依赖项与新的 REST 客户端依赖项进行匹配。

The following table matches the legacy RESTEasy Classic-based REST Client dependencies with the new REST Client ones.

Legacy Quarkus REST

quarkus-resteasy-client

quarkus-rest-client

quarkus-resteasy-client-jackson

quarkus-rest-client-jackson

quarkus-resteasy-client-jsonb

quarkus-rest-client-jsonb

quarkus-resteasy-client-jaxb

quarkus-rest-client-jaxb

quarkus-resteasy-client-mutiny

No replacement, natively supports Mutiny

Keycloak admin client

在使用`quarkus-rest-client`时,用户可以使用`quarkus-keycloak-admin-rest-client`通过利用 REST 客户端来管理目标 Keycloak 实例。

When using quarkus-rest-client, users can use the quarkus-keycloak-admin-rest-client to administer the target Keycloak instance by leveraging the rest client.

然而,在使用`quarkus-resteasy-client`时,用户必须使用`quarkus-keycloak-admin-resteasy-client`来访问相同的功能并使用基于 RESTEasy Classic 的旧版 REST 客户端。

When using quarkus-resteasy-client however, users must use quarkus-keycloak-admin-resteasy-client to access the same functionality and use the legacy RESTEasy Classic-based REST Client.

OIDC

在使用`quarkus-rest-client`时,用户可以使用`quarkus-rest-client-oidc-filter`extension 从 OpenID Connect 和 OAuth 2.0 兼容授权服务器获取和刷新访问令牌。

When using quarkus-rest-client, users can use the quarkus-rest-client-oidc-filter extension to acquire and refresh access tokens from OpenID Connect and OAuth 2.0 compliant Authorization Servers.

然而,在使用`quarkus-resteasy-client`时,用户必须使用`quarkus-resteasy-client-oidc-filter`来访问相同的功能。

When using quarkus-resteasy-client however, users must use quarkus-resteasy-client-oidc-filter to access the same functionality.

同样,`quarkus-rest-client-oidc-token-propagation`允许传统 REST 的用户传播当前的`Bearer`或`Authorization Code Flow`访问令牌。

Similarly, quarkus-rest-client-oidc-token-propagation allows user of the legacy REST to propagate the current Bearer or Authorization Code Flow access tokens.

然而,在使用`quarkus-resteasy-client`时,用户必须使用`quarkus-resteasy-client-oidc-token-propagation`来访问相同的功能。

When using quarkus-resteasy-client however, users must use quarkus-resteasy-client-oidc-token-propagation to access the same functionality.

Custom extensions

这是一个高级部分,仅需要由开发自定义扩展的用户阅读,这些扩展依赖于 Jakarta REST 和/或 REST 客户端功能。

This is an advanced section that only needs to be read by users who have developed custom extensions that depend on Jakarta REST and / or REST Client functionality.

Dependencies

首要顾虑是自定义扩展应明确依赖于 Quarkus REST 还是同时支持 RESTEasy 组件,并由用户决定。如果该扩展是一些通用扩展,那么可能合理选择后者选项,而当特定用户/应用程序集使用自定义扩展时,前者选项最易于采纳。

A first concern is whether custom extensions should depend on Quarkus REST explicitly, or alternatively support both RESTEasy flavors and leave it to the user to decide. If the extension is some general purpose extension, it probably makes sense to choose the latter option, while the former option is easiest to adopt when the custom extension is used by a specific set of users / applications.

在选择支持这两个扩展时,该自定义扩展的部署模块通常将依赖于 SPI 模块——quarkus-jaxrs-spi-deploymentquarkus-resteasy-common-spiquarkus-rest-spi-deployment,而运行时模块将对 RESTEasy 两个组件的运行时模块存在 optional 依赖关系。

When opting for supporting both extensions, the deployment module of the custom extension will usually depend on the SPI modules - quarkus-jaxrs-spi-deployment, quarkus-resteasy-common-spi, quarkus-rest-spi-deployment, while the runtime modules will have optional dependencies on the runtime modules of both RESTEasy flavors.

一些很好的例子说明 Quarkus 如何在核心存储库中使用此策略来支持这两个 RESTEasy 组件,可参见 [此处]([role="bare"][role="bare"]https://github.com/quarkusio/quarkus/pull/21089) 和 [此处]([role="bare"][role="bare"]https://github.com/quarkusio/quarkus/pull/20874)。

A couple good examples of how Quarkus uses this strategy to support both RESTEasy flavors in the core repository can be seen [here]([role="bare"]https://github.com/quarkusio/quarkus/pull/21089) and [here]([role="bare"]https://github.com/quarkusio/quarkus/pull/20874).

通常,支持这两个组件不需要该自定义扩展的两个不同版本。这样的选择只在扩展使用者(即 Quarkus 应用程序)希望不必自己选择 RESTEasy 版本时才是严格需要的。

In general, it should not be needed to have two different versions of the custom extension to support both flavors. Such a choice is only strictly necessary if it is desired for the extension consumers (i.e. Quarkus applications) to not have to select a RESTEasy version themselves.

Resource and Provider discovery

在其运行时模块中包含 Jakarta REST 资源、提供程序或 REST 客户端接口且依赖于 Jandex 索引以发现它们的自定义扩展(例如,因为它们有一个空的 META-INF/beans.xml 文件),不必执行任何其他设置以使 Quarkus REST 发现它们。

Custom extensions that contain Jakarta REST Resources, Providers or REST Client interfaces in their runtime modules and depend on Jandex indexing for their discovery (for example because they have an empty META-INF/beans.xml file) don’t have to perform any additional setup to make these discoverable by Quarkus REST.

Provider registration via Build Items

通过构建项目使用 io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem 构建项目在 RESTEasy Classic 中注册提供程序。然而,使用 Quarkus REST 时,扩展需要使用特定的构建项目,如 io.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItemio.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItem

Extensions that register providers via build items use the io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem build item in RESTEasy Classic. With Quarkus REST however, extensions need to use specific build items, such as io.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItem and io.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItem.

REST Client

作为使用 RESTEasy 客户端的 Quarkus 应用程序一部分运行的任何代码,都可以安全地使用 REST 客户端,因为它在应用程序的静态初始化阶段已经配置了所有必要的设置。

Any code that is run as part of a Quarkus application that used the RESTEasy Client, can safely use the REST Client, as all necessary setup for it has been done at the application’s static-init phase.