Skip to content

Migration Guide 3.26

Yoann Rodière edited this page Jul 30, 2025 · 12 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.

Legacy config classes support is gone

As announced previously, we retired the legacy config classes support in 3.26. They were deprecated since 3.19.

This change is all about extension development BUT…​ you need all the extensions of your applications to be in line with this change.

For your application

We already fixed all the Quarkiverse extensions: you need to upgrade to their latest versions.

You also need to fix your custom extensions and get them released and updated. See the next paragraph for more details.

For your extensions

Your extensions need to be in compliance with this change:

  • @ConfigRoot should exclusively be used on interfaces in conjunction with @ConfigMapping - the deprecated attributes have also been removed

  • @ConfigItem has been dropped as it was only used for legacy config classes

The extension annotation processor will also complain with an error if it encounters a legacy config class.

The compatibility legacy config classes we kept in 3.19-3.25 are also gone:

  • GlobalDevServicesConfig: use DevServicesConfig instead

  • HttpConfiguration: use VertxHttpConfig instead

  • HttpBuildTimeConfig: use VertxHttpBuildTimeConfig instead

We recommend you base your extensions on 3.20 LTS from now on, and start a specific maintenance branch for 3.15 LTS if you think it’s required for your extension.

Hibernate ORM

JSON/XML mapping

In previous versions of Quarkus, the "format mappers" used by Hibernate to serialize JSON/XML stored in the dabatase, used to rely, by default, on the global serialization settings initially meant for the REST layer.

In general, it is a good idea to separate the serialization/deserialization of data you write into the database from the serialization/deserialization of the REST layer. This allows to keep the DB format more stable and prevents unnecessary migrations.

For this reason, Quarkus 3.26 will now fail by default if:

  1. The application has a Hibernate mapping involving XML or JSON stored in the database.

  2. The XML or JSON serialization settings for the REST layer are customized.

If you are in this case, you should review your database serialization settings, as explained in the following subsections.

Jackson-based JSON serialization

If the ObjectMapper customization applied in your application does not affect the format of the JSON stored in the database, you can just bypass that ObjectMapper with quarkus.hibernate-orm.mapping.format.global=ignore.

Otherwise, implement a custom FormatMapper bean as described here. Start by a delegating format mapper:

@io.quarkus.hibernate.orm.JsonFormat // (1)
@io.quarkus.hibernate.orm.PersistenceUnitExtension("pu-name-if-non-default-one") // (2)
public class JsonFormatMapper implements FormatMapper {

    private final org.hibernate.type.format.jackson.JacksonJsonFormatMapper delegate;

    @Inject
    public JsonFormatMapper(ObjectMapper objectMapper) {  // (3)
        this.delegate = new  org.hibernate.type.format.jackson.JacksonJsonFormatMapper(objectMapper); // (4)
    }

    @Override
    public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.fromString(charSequence, javaType, wrapperOptions); // (5)
    }

    @Override
    public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.toString(value, javaType, wrapperOptions); // (5)
    }
}
  1. Mark your custom mapper with @io.quarkus.hibernate.orm.JsonFormat for Quarkus to pick it up and apply.

  2. Specifying the PersistenceUnitExtension is only required if the mapper has to be applied to a non-default persistent unit.

  3. Inject the ObjectMapper.

  4. Create a delegate that uses the injected object mapper.

  5. Delegate serialization/deserialization operations.

This will preserve the behaviour from previous versions of Quarkus.

From here, you can either:

  • Keep using this delegating format mapper if you are fine with relying on the globally configured ObjectMapper and be dependent on the REST layer serialization needs

  • Or prepare and test migration scripts to update your JSON data. You can either pick the default format that Hibernate ORM uses, in which case you can remove the custom FormatMapper and then bypass the built-in mapper with quarkus.hibernate-orm.mapping.format.global=ignore, or alternatively, adapt the FormatMapper implementation to format JSON according to your needs.

JSON-B-based JSON serialization

This scenario is exactly the same as the one for the Jackson-based mapper described above. The delegating format mapper in this case can look as follows:

@io.quarkus.hibernate.orm.JsonFormat // (1)
@io.quarkus.hibernate.orm.PersistenceUnitExtension("pu-name-if-non-default-one") // (2)
public class JsonbFormatMapper implements FormatMapper {

    private final org.hibernate.type.format.jakartajson.JsonBJsonFormatMapper delegate;

    @Inject
    public JsonFormatMapper(Jsonb jsonb) {  // (3)
        this.delegate = new  org.hibernate.type.format.jakartajson.JsonBJsonFormatMapper(jsonb); // (4)
    }

    @Override
    public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.fromString(charSequence, javaType, wrapperOptions); // (5)
    }

    @Override
    public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.toString(value, javaType, wrapperOptions); // (5)
    }
}
  1. Mark your custom mapper with @io.quarkus.hibernate.orm.JsonFormat for Quarkus to pick it up and apply.

  2. Specifying the PersistenceUnitExtension is only required if the mapper has to be applied to a non-default persistent unit.

  3. Inject the Jsonb.

  4. Create a delegate that uses the injected object mapper.

  5. Delegate serialization/deserialization operations.

JAXB-based XML serialization

For XML serialization, the problem is compounded by a change of serialization format for XML in Hibernate ORM 7.0.

While Quarkus’s built-in JAXB-based XML format mapper applies the legacy format, once it is removed, or bypassed with quarkus.hibernate-orm.mapping.format.global=ignore the format will become incompatible. To mitigate the problem, you can start by creating a mapper that would delegate to Hibernate ORM’s mapper as follows:

@io.quarkus.hibernate.orm.XmlFormat // (1)
@io.quarkus.hibernate.orm.PersistenceUnitExtension("pu-name-if-non-default-one") // (2)
public class XmlFormatMapper implements FormatMapper {
    private static final boolean isLegacyFormat = true;
    private final org.hibernate.type.format.jaxb.JaxbXmlFormatMapper delegate = new org.hibernate.type.format.jaxb.JaxbXmlFormatMapper(isLegacyFormat); // (3)

    @Override
    public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.fromString(charSequence, javaType, wrapperOptions); // (4)
    }

    @Override
    public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.toString(value, javaType, wrapperOptions); // (4)
    }
}
  1. Mark your custom mapper with @io.quarkus.hibernate.orm.XmlFormat for Quarkus to pick it up and apply.

  2. Specifying the PersistenceUnitExtension is only required if the mapper has to be applied to a non-default persistent unit.

  3. Create a delegate that uses the legacy format.

  4. Delegate serialization/deserialization operations.

This will preserve the behaviour from previous versions of Quarkus.

From here, you can either:

  • Keep using this delegating format mapper if you are fine with relying on a legacy format for the time being.

  • Or prepare and test migration scripts to update your XML data. You can either pick the default format that Hibernate ORM uses, in which case you can remove the custom FormatMapper and then bypass the built-in mapper with quarkus.hibernate-orm.mapping.format.global=ignore, or alternatively, adapt the FormatMapper implementation to format XML according to your needs.

For more information about the XML format changes, please refer to the Hibernate ORM’s migration guide.

Migration guides

Current version


LTS versions


Next version in main


Clone this wiki locally