-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Migration Guide 3.26
Note
|
We highly recommend the use of Items marked below with ⚙️ ✅ are automatically handled by |
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.
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.
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
: useDevServicesConfig
instead -
HttpConfiguration
: useVertxHttpConfig
instead -
HttpBuildTimeConfig
: useVertxHttpBuildTimeConfig
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.
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:
-
The application has a Hibernate mapping involving XML or JSON stored in the database.
-
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.
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)
}
}
-
Mark your custom mapper with
@io.quarkus.hibernate.orm.JsonFormat
for Quarkus to pick it up and apply. -
Specifying the
PersistenceUnitExtension
is only required if the mapper has to be applied to a non-default persistent unit. -
Inject the
ObjectMapper
. -
Create a delegate that uses the injected object mapper.
-
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 withquarkus.hibernate-orm.mapping.format.global=ignore
, or alternatively, adapt theFormatMapper
implementation to format JSON according to your needs.
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)
}
}
-
Mark your custom mapper with
@io.quarkus.hibernate.orm.JsonFormat
for Quarkus to pick it up and apply. -
Specifying the
PersistenceUnitExtension
is only required if the mapper has to be applied to a non-default persistent unit. -
Inject the
Jsonb
. -
Create a delegate that uses the injected object mapper.
-
Delegate serialization/deserialization operations.
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)
}
}
-
Mark your custom mapper with
@io.quarkus.hibernate.orm.XmlFormat
for Quarkus to pick it up and apply. -
Specifying the
PersistenceUnitExtension
is only required if the mapper has to be applied to a non-default persistent unit. -
Create a delegate that uses the legacy format.
-
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 withquarkus.hibernate-orm.mapping.format.global=ignore
, or alternatively, adapt theFormatMapper
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.