Platform
The Quarkus extension ecosystem consists of the Quarkus extensions developed and maintained by the community, including the Quarkus core development team. While the Quarkus ecosystem (sometimes also referred to as the "Quarkus universe") includes all the Quarkus extensions ever developed, there is also a concept of a Quarkus platform.
Quarkus Platform
The fundamental promise of a Quarkus platform is any combination of the Quarkus extensions the platform consists of can be used in the same application without causing any conflict for each other. Each organization creating their Quarkus platform may establish their own criteria for the extensions to be accepted into the platform and the means to guarantee the compatibility between the accepted extensions.
Quarkus Platform BOM
Each Quarkus Platform is expected to provide a Maven BOM artifact that
-
imports a chosen version of
io.quarkus:quarkus-bom
(the platform BOM may be flattened at the end, but it has to be based on some version ofio.quarkus:quarkus-bom
) -
includes all the Quarkus extension artifacts (the runtime and the deployment ones) the platform consists of
-
includes all the necessary third-party artifacts that align the transitive dependency versions of the platform extensions to guarantee compatibility between them
-
includes the platform JSON descriptor artifact
-
possibly includes the platform configuration properties artifacts
Quarkus applications that want to include extensions from a Quarkus platform will be importing the Quarkus platform BOM.
Quarkus Platform Descriptor
Quarkus platform descriptor is a JSON artifact that provides information
about the platform and its extensions to the Quarkus
tools. E.g. https://code.quarkus.io/ and the Quarkus command line tools
consult this descriptor to list, add and remove extensions to/from the
project on user’s request. This artifact is also used as a Quarkus platform
identifier. When Quarkus tools need to identify the Quarkus platform(s) used
in the project, they will analyze the dependency version constraints of the
project (the effective list of the managed dependencies from the
dependencyManagement
section in Maven terms) looking for the platform
descriptor artifact(s) among them. Given that the platform descriptors are
included into the Quarkus platform BOMs, every Quarkus application will
inherit the platform descriptor artifact from the imported platform BOM(s)
as a dependency version constraint (managed dependency in Maven terms).
To be able to easily identify Quarkus platform descriptors among the project’s dependency constraints, the platform descriptor Maven artifact coordinates should follow the following naming convention:
-
the
groupId
of the descriptor artifact should match thegroupId
of the corresponding Quarkus Platform BOM; -
the
artifactId
of the descriptor artifact should be theartifactId
of the corresponding Quarkus Platform BOM with the-quarkus-platform-descriptor
suffix; -
the
classifier
of the descriptor artifact should match theversion
of the corresponding Quarkus Platform BOM; -
the
type
of the descriptor artifact should bejson
; -
the
version
of the descriptor artifact should match theversion
of the corresponding Quarkus Platform BOM.
As a string it will look like
<platform-bom-groupId>:<platform-bom-artifactId>-quarkus-platform-descriptor:<platform-version>:json:<platform-version>
E.g. the coordinates of the descriptor for the Quarkus BOM
io.quarkus.platform:quarkus-bom::pom:1.2.3
will be
io.quarkus.platform:quarkus-bom-quarkus-platform-descriptor:1.2.3:json:1.2.3
.
And for a custom Quarkus platform defined with BOM
org.acme:acme-bom::pom:555
it will be
org.acme:acme-bom-quarkus-platform-descriptor:555:json:555
.
The classifier matching the version of the platform may look confusing at
first. But this is what turns the descriptor into a true "fingerprint" of
the platform. In both Maven and Gradle, the effective set of the dependency
version constraints (or the managed dependencies) is obtained by merging all
the imported BOMs and version constraints specified individually in the
current project and also its parent(s). The artifact classifier
is a part
of the dependency ID, which could be expressed as
groupId:artifactId:classifier:type
. Which means that if a project imports
a couple of BOMs, e.g. org.apple:apple-bom::pom:1.0
and
org.orange:orange-bom::pom:1.0
, and each of these two BOMs imports a
different version io.quarkus.platform:quarkus-bom::pom
, the Quarkus
tools will be able to detect this fact and make the user aware of it, since
it might not be a safe combination. If the descriptor artifact didn’t
include the classifier containing the version of the platform then the tools
wouldn’t be able to detect a potentially incompatible mix of different
versions of the same platform in the same project.
The platform descriptor will normally be generated using a Maven plugin, e.g.
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-platform-descriptor-json-plugin</artifactId>
<version>${quarkus.version}</version> (1)
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>generate-extensions-json</goal> (2)
</goals>
</execution>
</executions>
<configuration>
<bomGroupId>${quarkus.platform.group-id}</bomGroupId> (3)
<bomArtifactId>${quarkus.platform.artifact-id}</bomArtifactId> (4)
<bomVersion>${quarkus.platform.version}</bomVersion> (5)
<overridesFile>${overridesfile}</overridesFile> (6)
<resolveDependencyManagement>true</resolveDependencyManagement> (7)
</configuration>
</plugin>
1 | the version of the quarkus-platform-descriptor-json-plugin |
2 | generate-extensions-json is the goal generating the platform descriptor |
3 | the groupId of the platform BOM |
4 | the artifactId of the platform BOM |
5 | the version of the platform BOM |
6 | this parameter is optional, it allows to override some metadata from the Quarkus extension descriptors found in every runtime extension artifact from which the platform descriptor is generated |
7 | this parameter is also optional and defaults to false. It has to be set to
true in case the platform BOM is not generated and is not
flattened. Which for example is the case for io.quarkus:quarkus-bom . |
Quarkus Platform Properties
A Quarkus platform may provide its own default values for some configuration options.
Quarkus is using SmallRye
Config for wiring application configuration. A Quarkus platform may be used
as another source of configuration in the hierarchy of the configuration
sources dominated by the application’s application.properties
.
To provide platform-specific defaults, the platform needs to include a dependency version constraint in its BOM for a properties artifact whose coordinates follow the following naming convention:
-
the
groupId
of the properties artifact should match thegroupId
of the corresponding Quarkus Platform BOM; -
the
artifactId
of the properties artifact should be theartifactId
of the corresponding Quarkus Platform BOM with the-quarkus-platform-properties
suffix; -
the
classifier
of the descriptor artifact should be left empty/null; -
the
type
of the descriptor artifact should beproperties
; -
the
version
of the descriptor artifact should match theversion
of the corresponding Quarkus Platform BOM.
The properties artifact itself is expected to be a traditional properties
file that will be loaded into an instance of java.util.Properties
class.
At this point, platform properties are only allowed to provide the default
values for a restricted set of configuration options. The property names in
the platform properties file must be prefixed with the platform. suffix.
|
Extension developers that want to make their configuration options
platform-specific should set their default values to properties that start
with the platform.
suffix. Here is an example:
package io.quarkus.deployment.pkg;
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
@ConfigMapping(prefix = "quarkus")
public interface NativeConfig {
/**
* The docker image to use to do the image build
*/
@WithDefault("${platform.quarkus.native.builder-image}")
String builderImage();
}
In this case the default value for quarkus.native.builder-image
will be
provided by the platform. The user will still be able to set the desired
value for quarkus.native.builder-image
in its application.properties
, of
course. But in case it’s not customized by the user, the default value will
be coming from the platform properties. A platform properties file for the
example above would contain:
platform.quarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21
There is also a Maven plugin goal that validates the platform properties content and its artifact coordinates and also checks whether the platform properties artifact is present in the platform’s BOM. Here is a sample plugin configuration:
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-platform-descriptor-json-plugin</artifactId>
<version>${quarkus.version}</version>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>platform-properties</goal>
</goals>
</execution>
</executions>
</plugin>
Merging Quarkus Platform Properties
In case an application is importing more than one Quarkus platform and those
platforms include their own platform properties artifacts, the content of
those platform properties artifacts will be merged to form a single set of
properties that will be used for the application build. The order in which
the properties artifacts are merged will correspond to the order in which
they appear in the list of dependency version constraints of the application
(in the Maven terms that will correspond to the effective list of
application’s managed dependencies, i.e. the flattened managedDependencies
POM section).
The content of the properties artifacts found earlier will dominate over those found later among the application’s dependency constraints! |
That means if a platform needs to override a certain property value defined
in the platform it is based on, it will need to include its platform
properties artifact into the managedDependencies
section of its BOM before
importing the base platform.
For example, let’s assume org.acme:acme-quarkus-bom
platform extends the
io.quarkus:quarkus-bom
platform by importing its BOM. In case, the
org.acme:acme-quarkus-bom
platform were to override certain properties
defined in the io.quarkus:quarkus-bom-quarkus-platform-properties
included
in the io.quarkus:quarkus-bom
, the org.acme:acme-quarkus-bom
would have
to be composed as
<!-- skipped content -->
<artifactId>acme-quarkus-bom</artifactId>
<name>Acme - Quarkus - BOM</name>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<!-- Acme Quarkus platform properties -->
<dependency>
<groupId>org.acme</groupId>
<artifactId>acme-quarkus-bom-quarkus-platform-properties</artifactId>
<type>properties</type>
<version>${project.version}</version>
</dependency>
<!-- The base Quarkus BOM -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- skipped content -->
That way, the org.acme:acme-quarkus-bom
platform properties will appear
before those provided by the io.quarkus:quarkus-bom
properties and so will
be dominating at build time.