Skip to content

Migration Guide 3.9

Yoann Rodière edited this page Sep 24, 2024 · 35 revisions
Note

We highly recommend the use of quarkus update to update to a new version of Quarkus.

Items marked below with ⚙️ ✅ are automatically handled by quarkus update.

RESTEasy Reactive extensions renamed to Quarkus REST ⚙️ ✅

RESTEasy Reactive has been our default REST layer for a while and has always been supporting blocking workloads and the name was confusing.

Some users were not using it because they thought it wouldn’t work well for their usual blocking workloads. Some other users thought that when using RESTEasy Reactive, they had to use Hibernate Reactive, which is not true: you can use Hibernate ORM with Hibernate Reactive.

In Quarkus 3.9, we decided to rename RESTEasy Reactive to Quarkus REST.

While this change looks like a big change for you, we put Maven relocations in place and quarkus update will automatically update your projects to the new artifacts.

We tried hard to be consistent across our stack:

  • Extensions named -rest are extensions using Quarkus REST (and RESTEasy Reactive)

  • Extensions named -resteasy are extensions using RESTEasy Classic

The following extensions have been renamed:

Old name New name

quarkus-resteasy-reactive

quarkus-rest

quarkus-resteasy-reactive-jackson

quarkus-rest-jackson

quarkus-resteasy-reactive-jaxb

quarkus-rest-jaxb

quarkus-resteasy-reactive-jsonb

quarkus-rest-jsonb

quarkus-resteasy-reactive-kotlin

quarkus-rest-kotlin

quarkus-resteasy-reactive-kotlin-serialization

quarkus-rest-kotlin-serialization

quarkus-resteasy-reactive-links

quarkus-rest-links

quarkus-resteasy-reactive-qute

quarkus-rest-qute

quarkus-resteasy-reactive-servlet

quarkus-rest-servlet

quarkus-rest-client-reactive

quarkus-rest-client

quarkus-rest-client-reactive-jackson

quarkus-rest-client-jackson

quarkus-rest-client-reactive-jaxb

quarkus-rest-client-jaxb

quarkus-rest-client-reactive-jsonb

quarkus-rest-client-jsonb

quarkus-rest-client-reactive-kotlin-serialization

quarkus-rest-client-kotlin-serialization

quarkus-jaxrs-client-reactive

quarkus-rest-client-jaxrs

quarkus-keycloak-admin-client

quarkus-keycloak-admin-resteasy-client

quarkus-keycloak-admin-client-reactive

quarkus-keycloak-admin-rest-client

quarkus-oidc-client-filter

quarkus-resteasy-client-oidc-filter

quarkus-oidc-client-reactive-filter

quarkus-rest-client-oidc-filter

quarkus-oidc-token-propagation

quarkus-resteasy-client-oidc-token-propagation

quarkus-oidc-token-propagation-reactive

quarkus-rest-client-oidc-token-propagation

quarkus-csrf-reactive

quarkus-rest-csrf

quarkus-spring-web-resteasy-classic

quarkus-spring-web-resteasy

quarkus-spring-web-resteasy-reactive

quarkus-spring-web-rest

The configuration roots have also been changed:

Old config root New config root

quarkus.resteasy-reactive.*

quarkus.rest.*

quarkus.rest-client-reactive.*

quarkus.rest-client.*

quarkus.oidc-client-reactive-filter.*

quarkus.rest-client-oidc-filter.*

quarkus.oidc-token-propagation-reactive.*

quarkus.rest-client-oidc-token-propagation.*

quarkus.csrf-reactive.*

quarkus.rest-csrf.*

quarkus.oidc-client-filter.*

quarkus.resteasy-client-oidc-filter.*

quarkus.oidc-token-propagation.*

quarkus.resteasy-client-oidc-token-propagation.*

An automatic fallback mechanism has been put in place to fall back to the old configuration properties.

If you are an extension developer, you might also be impacted by these artifacts being renamed:

Old name New name

quarkus-resteasy-reactive-deployment

quarkus-rest-deployment

quarkus-resteasy-reactive-jackson-common

quarkus-rest-jackson-common

quarkus-resteasy-reactive-jackson-common-deployment

quarkus-rest-jackson-common-deployment

quarkus-resteasy-reactive-jackson-deployment

quarkus-rest-jackson-deployment

quarkus-resteasy-reactive-jaxb-common

quarkus-rest-jaxb-common

quarkus-resteasy-reactive-jaxb-common-deployment

quarkus-rest-jaxb-common-deployment

quarkus-resteasy-reactive-jaxb-deployment

quarkus-rest-jaxb-deployment

quarkus-resteasy-reactive-jsonb-common

quarkus-rest-jsonb-common

quarkus-resteasy-reactive-jsonb-common-deployment

quarkus-rest-jsonb-common-deployment

quarkus-resteasy-reactive-jsonb-deployment

quarkus-rest-jsonb-deployment

quarkus-resteasy-reactive-kotlin-deployment

quarkus-rest-kotlin-deployment

quarkus-resteasy-reactive-kotlin-serialization-common

quarkus-rest-kotlin-serialization-common

quarkus-resteasy-reactive-kotlin-serialization-common-deployment

quarkus-rest-kotlin-serialization-common-deployment

quarkus-resteasy-reactive-kotlin-serialization-deployment

quarkus-rest-kotlin-serialization-deployment

quarkus-resteasy-reactive-links-deployment

quarkus-rest-links-deployment

quarkus-resteasy-reactive-qute-deployment

quarkus-rest-qute-deployment

quarkus-resteasy-reactive-server-common

quarkus-rest-server-common

quarkus-resteasy-reactive-server-spi-deployment

quarkus-rest-server-spi-deployment

quarkus-resteasy-reactive-servlet-deployment

quarkus-rest-servlet-deployment

quarkus-resteasy-reactive-common

quarkus-rest-common

quarkus-resteasy-reactive-common-deployment

quarkus-rest-common-deployment

quarkus-rest-client-reactive-deployment

quarkus-rest-client-deployment

quarkus-rest-client-reactive-jackson-deployment

quarkus-rest-client-jackson-deployment

quarkus-rest-client-reactive-jaxb-deployment

quarkus-rest-client-jaxb-deployment

quarkus-rest-client-reactive-jsonb-deployment

quarkus-rest-client-jsonb-deployment

quarkus-rest-client-reactive-kotlin-serialization-deployment

quarkus-rest-client-kotlin-serialization-deployment

quarkus-rest-client-reactive-spi-deployment

quarkus-rest-client-spi-deployment

quarkus-jaxrs-client-reactive-deployment

quarkus-rest-client-jaxrs-deployment

quarkus-keycloak-admin-client-deployment

quarkus-keycloak-admin-resteasy-client-deployment

quarkus-keycloak-admin-client-reactive-deployment

quarkus-keycloak-admin-rest-client-deployment

quarkus-oidc-client-filter-deployment

quarkus-resteasy-client-oidc-filter-deployment

quarkus-oidc-client-reactive-filter-deployment

quarkus-rest-client-oidc-filter-deployment

quarkus-oidc-token-propagation-deployment

quarkus-resteasy-client-oidc-token-propagation-deployment

quarkus-oidc-token-propagation-reactive-deployment

quarkus-rest-client-oidc-token-propagation-deployment

quarkus-csrf-reactive-deployment

quarkus-rest-csrf-deployment

quarkus-spring-web-resteasy-classic-deployment

quarkus-spring-web-resteasy-deployment

quarkus-spring-web-resteasy-reactive-deployment

quarkus-spring-web-rest-deployment

SmallRye Reactive Messaging extensions renamed to Quarkus Messaging ⚙️ ✅

The SmallRye Reactive Messaging extensions have been renamed to quarkus-messaging-* to convey the fact that they also support blocking workloads.

While this change looks like a big change for you, we put Maven relocations in place and quarkus update will automatically update your projects to the new artifacts.

The following extensions have been renamed:

Old name New name

quarkus-smallrye-reactive-messaging

quarkus-messaging

quarkus-smallrye-reactive-messaging-amqp

quarkus-messaging-amqp

quarkus-smallrye-reactive-messaging-kafka

quarkus-messaging-kafka

quarkus-smallrye-reactive-messaging-mqtt

quarkus-messaging-mqtt

quarkus-smallrye-reactive-messaging-pulsar

quarkus-messaging-pulsar

quarkus-smallrye-reactive-messaging-rabbitmq

quarkus-messaging-rabbitmq

The configuration root has also been changed from quarkus.smallrye-reactive-messaging. to quarkus.messaging..

An automatic fallback mechanism has been put in place to fall back to the old configuration properties.

If you are an extension developer, you might also be impacted by these artifacts being renamed:

Old name New name

quarkus-smallrye-reactive-messaging-deployment

quarkus-messaging-deployment

quarkus-smallrye-reactive-messaging-kotlin

quarkus-messaging-kotlin

quarkus-smallrye-reactive-messaging-amqp-deployment

quarkus-messaging-amqp-deployment

quarkus-smallrye-reactive-messaging-kafka-deployment

quarkus-messaging-kafka-deployment

quarkus-smallrye-reactive-messaging-mqtt-deployment

quarkus-messaging-mqtt-deployment

quarkus-smallrye-reactive-messaging-pulsar-deployment

quarkus-messaging-pulsar-deployment

quarkus-smallrye-reactive-messaging-rabbitmq-deployment

quarkus-messaging-rabbitmq-deployment

Panache annotation processor removed for Hibernate ORM/Hibernate Reactive/MongoDB ⚙️ ✅

For externally defined entities, in Hibernate ORM with Panache, Hibernate Reactive with Panache, and MongoDB with Panache, we used to require to run the io.quarkus:quarkus-panache-common annotation processor, which would be automatic when found in the classpath, except in case you overrode the set of annotation processors to run in your build tool, in which case you had to add the annotation processor explicitly in your build tool.

With Quarkus 3.9, this is no longer required, and the annotation processor has been removed, so you should remove all usage of the io.quarkus:quarkus-panache-common annotation processor from your build files.

For Maven builds, this would be located here:

<build>
    <plugins>
        [...]
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.12.0</version> <!-- Necessary for proper dependency management in annotationProcessorPaths -->
            <configuration>
                <annotationProcessorPaths>
                    <path>
                        <groupId>io.quarkus</groupId>
                        <artifactId>quarkus-panache-common</artifactId>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
        [...]
    </plugins>
</build>

For Gradle, this would be located here:

dependencies {
    annotationProcessor "io.quarkus:quarkus-panache-common"
}

Datasources

Multiple non-XA datasources in the same transaction now trigger a failure

Starting with Quarkus 3.9, attempting to access multiple non-XA datasources in the same transaction would result in an exception similar to the one below, due to a significant risk of non-transactional behavior:

...
Caused by: java.sql.SQLException: Exception in association of connection to existing transaction
        at io.agroal.narayana.NarayanaTransactionIntegration.associate(NarayanaTransactionIntegration.java:130)
        ...
Caused by: java.sql.SQLException: Failed to enlist. Check if a connection from another datasource is already enlisted to the same transaction
        at io.agroal.narayana.NarayanaTransactionIntegration.associate(NarayanaTransactionIntegration.java:121)
        ...

For more information, recommendations, and ways to change this behavior, see this section of the documentation.

OpenTelemetry

Semantic convention changes

Current Semantic Conventions for HTTP will soon change and the current conventions are deprecated for removal soon.

Please move to the new conventions by setting the new property quarkus.otel.semconv-stability.opt-in to http for the new conventions or http/dup to produce duplicated old and new conventions attributes.

Please check the OpenTelemetry extension configuration reference for more details and full set of changes at the HTTP semantic convention stability migration guide from OpenTelemetry.

Security events as OTel Events

Quarkus now has the ability to export security events as OpenTelemetry Events, stored inside spans. This is not done by default and to activate you must to set this build time (only) configuration property:

quarkus.otel.security-events.enabled=true

The HAL wrappers class signatures have been updated to include the type of elements in the collection as listed below.

  • HalCollectionWrapper<T>

  • HalEntityWrapper<T>

You should add the type argument everywhere you use the HAL wrapper classes.

The preferred way of creating the wrapper classes changed from using the constructor to use helper methods exposed on the io.quarkus.hal.HalService bean as shown below:

@Path("/records")
public class RecordsResource {

    @Inject
    HalService halService;

    @GET
    @Produces({ MediaType.APPLICATION_JSON, RestMediaType.APPLICATION_HAL_JSON })
    @RestLink(rel = "list")
    public HalCollectionWrapper<Record> getAll() {
        List<Record> list = // ...
        HalCollectionWrapper<Record> halCollection = halService.toHalCollectionWrapper( list, "collectionName", Record.class);
        // ...
        return halCollection;
    }

    @GET
    @Produces({ MediaType.APPLICATION_JSON, RestMediaType.APPLICATION_HAL_JSON })
    @Path("/{id}")
    @RestLink(rel = "self")
    @InjectRestLinks(RestLinkType.INSTANCE)
    public HalEntityWrapper<Record> get(@PathParam("id") int id) {
        Record entity = // ...
        HalEntityWrapper<Record> halEntity = halService.toHalWrapper(entity);
        // ...
        return halEntity;
    }
}

Creating the wrappers using the constructors will still work for now, but this might change in the future.

RESTEasy Reactive: Filters on non REST paths

In the pre 3.9 versions, if you have a JAX-RS Filter, that filter will run, even in the case that the requested resource was not a REST resource. This will not happen anymore. Filters for JAX-RS will now only run on JAX-RS resources. In the case that you want your Filters to also run on non JAX-RS resource, you need to add your own ExceptionMapper:

package io.quarkus.resteasy.reactive.server.test.customproviders;

import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

@Provider
public class NotFoundExeptionMapper implements ExceptionMapper<NotFoundException> {
    @Override
    public Response toResponse(NotFoundException exception) {
        return Response.status(404).build();
    }
}

Now, JAX-RS becomes responsible for the Not Found resources, and the Filter will run. In the pre-3.9 version where this always happens, it makes it impossible for other extensions to handle Not Found.

Elasticsearch/OpenSearch

Dev Services

The Elasticsearch/OpenSearch Dev Services now default to starting:

  • Elasticsearch 8.12, instead of 8.9 previously

  • OpenSearch 2.11, instead of 2.9 previously

To force the use of a specific distribution (Elasticsearch vs. OpenSearch) or version, configure the container image explicitly.

Database schema changed for outbox-polling system tables

The Quarkus extension for Hibernate Search with outbox-polling relies on system tables in your database, and with Quarkus 3.9 the schema of these system tables may need to change.

See this section of the Hibernate Search migration guide for information on how to migrate your database schema if you were using that extension.

If you cannot update your database schema at the moment, you can use the following settings to restore previous defaults:

  • For the default persistence unit:

    quarkus.hibernate-search-orm.coordination.entity-mapping.agent.uuid-type=char
    quarkus.hibernate-search-orm.coordination.entity-mapping.outbox-event.uuid-type=char
  • For named persistence units:

    quarkus.hibernate-search-orm."persistence-unit-name".coordination.entity-mapping.agent.uuid-type=char
    quarkus.hibernate-search-orm."persistence-unit-name".coordination.entity-mapping.outbox-event.uuid-type=char

Update to Infinispan 15

Prior to Quarkus 3.9 and the Infinispan 15 integration, queries were executed by calling the following code: .Query.java

QueryFactory queryFactory = Search.getQueryFactory(booksCache); (1)
Query query = queryFactory.create("from book_sample.Book");
List<Book> list = query.execute().list();
  1. Breaking change in 3.9

This code won’t work anymore since RemoteCache is now an @ApplicationScoped proxy bean. Search.getQueryFactory will raise a ClassCastException. Remove the indirection by using the query method in the RemoteCache API as follows.

Query<Book> query = booksCache.<Book>query("from book_sample.Book");
List<Book> list = query.execute().list();

Keystore and trust store default format change

In 3.9, JKS is no longer the default keystore and trust store format. Quarkus makes an educated guess based on the file extension:

  • .pem, .crt and .key are read as PEM certificates and keys

  • .jks, .keystore and .truststore are read as JKS key stores and trust stores

  • .p12, .pkcs12 and .pfx are read as PKCS12 key stores and trust stores

If your file does not use one of these extensions, you need to set the format using:

quarkus.http.ssl.certificate.key-store-file-type=JKS # or P12 or PEM
quarkus.http.ssl.certificate.trust-store-file-type=JKS # or P12 or PEM

JKS is less and less used. Since Java 9, the default keystore format in Java is PKCS12. The most significant difference between JKS and PKCS12 is that JKS is a format specific to Java. At the same time, PKCS12 is a standardized and language-neutral way of storing encrypted private keys and certificates.

JUnit Pioneer version not enforced anymore

The org.junit-pioneer:junit-pioneer dependency version is not enforced by the Quarkus BOM anymore. Make sure you define the version in your build files if you are using this dependency.

GraalVM SDK update ⚙️ ✅

In Quarkus 3.8.3, we updated the GraalVM SDK artifacts version to 23.1.2. It was an oversight and should have been done long ago.

If you are developing extensions containing GraalVM substitutions, it is highly recommended to replace the org.graalvm.sdk:graal-sdk dependency with org.graalvm.sdk:nativeimage, that only contains the classes required to develop substitutions.

Also if you are using the Javascript polyglot features of GraalVM, org.graalvm.js:js should be replaced by:

  • org.graalvm.polyglot:js-community if you are using the community version of GraalVM

  • org.graalvm.polyglot:js if you are using the enterprise version of GraalVM

While the first change is handled by quarkus update, the second one has to be done manually depending on your GraalVM distribution of choice.

quarkus-app directory creation

Prior to Quarkus 3.9, the quarkus-app directory was always created in the build system’s output directory, regardless of the type of artifact being produced. This errorneous behavior has been fixed in Quarkus 3.9. Practically this which means that quarkus-app will only be created when the artifact being produced is a fast-jar (which is the default produced artifact if nothing has been configured).

Current Version

Migration Guide 3.16

Next Version

Migration Guide 3.17

Clone this wiki locally