Build lifecycle
Logging Parent extends the standard Maven default (build) lifecycle that runs on a plain
./mvnw verify
with three kinds of additions:
-
Additional checks that fail the build when a rule is violated,
-
Additional generated artifacts that are generated and attached or embedded into your JARs, and
-
Artifact transformations applied to the POM before it is published.
Some of these additions come from Logging Parent itself, some are inherited from the ASF Parent POM, and some are activated only when a particular activator file is present in your project. Each origin is called out below.
Beyond a plain ./mvnw verify, the parent also offers two opt-in mechanisms:
-
Optional lifecycle extensions that you enable on the command line to modify a build, and
-
Additional commands whose default goal performs a single task on its own.
Overview
The following table maps each addition to the Maven phase it binds to.
Everything listed here is triggered by a plain ./mvnw verify, unless it is marked as conditional on an activator file.
| Phase | Origin | Additions |
|---|---|---|
|
||
|
Logging Parent |
|
|
||
|
Logging Parent |
|
|
Logging Parent |
|
|
Logging Parent |
|
|
Logging Parent |
|
|
Logging Parent |
|
Additional checks
The checks below run automatically during ./mvnw verify.
The trickier ones link to a debugging recipe in Troubleshooting.
Maven & Java version
Phase: validate.
Enforced by the ASF Parent POM.
To build an Apache Logging Services project you need:
-
a JDK 17 (the build pins the major version
17, not a later one), and -
Maven 3.8.1 or later, most conveniently through the bundled Maven Wrapper (
./mvnw).
Both requirements are checked by the maven-enforcer-plugin inherited from the ASF Parent POM, through its requireJavaVersion and requireMavenVersion rules.
These rules can be modified using the properties below:
| Property | Controls | Default |
|---|---|---|
|
Range of JDK versions allowed to run the build |
|
|
Range of Maven versions allowed to run the build |
|
|
Java bytecode level the sources are compiled to |
|
Although most artifacts still target Java 8 bytecode (through the javac --release 8 flag), JDK 17 is required to run the Maven plugins in use and to keep builds reproducible.
Bytecode generation can differ between JDK major versions, so pinning a single one keeps the output byte-for-byte stable.
|
JDK 17 also requires the |
Some projects (currently only Log4j) additionally run their test suites against a real JDK 8 through
Maven Toolchains
in CI.
This proves runtime compatibility with the Java 8 platform, beyond the bytecode and API-surface guarantees that --release 8 provides on its own.
Order-independent dependency resolution
Phase: validate.
Maven’s default conflict mediation (nearest-wins, ties broken by declaration order) can resolve a dependency to a version lower than some transitive dependency requires, and the outcome can shift when dependencies are reordered.
The maven-enforcer-plugin requireUpperBoundDeps rule forbids this: it fails whenever a resolved version is lower than the highest one required across the graph.
The fix is to pin that dependency to at least the highest required version, making resolution order-independent. See the Order-independent dependency resolution recipe for how to read the error and adjust the pin.
|
Pinning a transitive dependency in your |
Code style
Code style is enforced by the spotless-maven-plugin in the verify phase, with one exception: the ban on wildcard imports is a maven-enforcer-plugin rule that runs earlier, in the validate phase.
The following rules apply:
- All files
-
Line endings are normalized to UNIX (
LF) and the ASF license header is required. Set a.gitattributesfile so that Git checks files out withLFon every platform. For example:*.properties text lf *.java text lf *.yaml text lf *.yml text lf *.xml text lf # Only this file needs to have CRLF line endings /mvnw.cmd text crlf - Java
-
Sources follow the Palantir Java format, and imports must be explicit (wildcard imports are banned).
- XML, POM,
.properties& YAML -
pom.xmlis sorted with the Spotless sortPom step; XML and YAML files also have trailing whitespace trimmed and a final newline enforced.
Most violations are fixed automatically by:
./mvnw spotless:apply
Anything the formatter cannot fix must be corrected by hand.
|
The Spotless configuration must stay in sync with the project’s |
Changelog validation
Phase: validate.
Activated by src/changelog/.
Apache Logging Services projects track their release notes as individual XML files under src/changelog/, managed by the log4j-changelog-maven-plugin.
When that directory is present, the xml-maven-plugin validates every entry against the Log4j Changelog schema, so a malformed entry fails the build early instead of breaking release-note generation later.
The schema is documented on the Log4j XML schema page.
Static analysis
Two static analysis tools scan the code on every build.
- Error Prone
-
Phase:
compile. Bundled into themaven-compiler-plugin(alongside-Xlint:all), it catches common Java mistakes as the code compiles. Its checks are fixed by Logging Parent and are not configurable per project. - SpotBugs + FindSecBugs
-
Phase:
verify. Thespotbugs-maven-pluginruns SpotBugs together with the FindSecBugs plugin for security-oriented bug patterns. False positives can be suppressed by adding aspotbugs-exclude.xmlfile to the project root; its presence alone activates the exclusion filter.
License validation
Phase: verify.
The apache-rat-plugin verifies that the project complies with the
ASF Source Header and Copyright Notice Policy, failing the build when a file is missing the required ASF license header.
Files that legitimately cannot carry a header or have been exempted from carrying one have been added to an exclude list.
API compatibility
Phase: verify.
Public APIs must not change without an explicit version bump.
The bnd-baseline-maven-plugin compares each module’s exported packages against their last release and enforces OSGi semantic versioning: a backward-compatible addition needs a minor increment, a breaking change a major one, and an internal-only fix a micro one.
Package versions are declared with the @Version annotation in each package’s package-info.java.
When a change is not matched by the right increment, the build fails with a table reporting the detected delta (MICRO, MINOR, or MAJOR) and the version the plugin suggests.
The rules for choosing the increment, and how to resolve such a failure, are explained in the API compatibility recipe.
Additional generated artifacts
Beyond the main JAR, the build attaches or embeds the following.
OSGi manifest
Phase: process-classes.
The bnd-maven-plugin generates an OSGi META-INF/MANIFEST.MF and hands it to the maven-jar-plugin, which packages it instead of its own default manifest.
BND derives the manifest from the compiled bytecode:
-
Bundle-SymbolicNameis computed from thegroupIdandartifactId; -
Export-Packagelists the packages annotated withorg.osgi.annotation.bundle.Exportin theirpackage-info.java; -
Import-Packageis inferred from the packages the code actually references.
This automatic inference is correct in the vast majority of cases, but a few situations must be declared explicitly, for example an optional dependency, whose import BND marks as mandatory unless told otherwise. Such cases can be tuned through the following properties, without redefining the whole BND configuration:
| Property | Purpose | Default |
|---|---|---|
|
Extra |
(empty) |
|
Override the computed |
derived from |
|
Value of the |
|
|
Arbitrary extra BND instructions, appended last. |
(empty) |
For the full set of bnd-* properties and worked examples, see Usage.
JPMS module descriptor
Phase: process-classes.
The same bnd-maven-plugin execution that produces the OSGi manifest also synthesizes a JPMS module-info descriptor from the same metadata.
This gives each module a proper, stable module name and its requires, exports, provides, and uses directives without a hand-written module-info.java, which could not target Java 8 anyway.
The module name defaults to the Bundle-SymbolicName, and the requires directives are inferred from the imported packages.
When that inference needs adjusting, use the following properties:
| Property | Purpose | Default |
|---|---|---|
|
Override the generated JPMS module name |
the |
|
Refine the computed |
(empty) |
|
To keep incremental recompiles working, a The same deletion, however, makes the classes folder look modified on every invocation.
Use |
ServiceLoader descriptor
Phase: process-classes.
java.util.ServiceLoader requires a provider-registration file under META-INF/services/ and, on the module path, matching provides and uses directives in module-info.
Rather than maintaining these by hand, Logging Parent lets BND generate them from two annotations:
aQute.bnd.annotation.spi.ServiceProvider-
Placed on a service implementation, it registers the class in the appropriate
META-INF/services/<service>file and adds aprovides <service> with <implementation>directive to the JPMS descriptor. aQute.bnd.annotation.spi.ServiceConsumer-
Placed on a type that looks services up through
ServiceLoader, it adds the matchinguses <service>directive to the JPMS descriptor.
Driving both the class-path (META-INF/services/) and module-path (module-info) registrations from a single annotation keeps the two representations from drifting apart.
CycloneDX SBOM
Phase: package.
The cyclonedx-maven-plugin generates a
CycloneDX Software Bill of Materials (SBOM) for every module, describing its resolved dependencies.
Each SBOM is attached as an XML artifact with the cyclonedx classifier (<artifactId>-<version>-cyclonedx.xml) and carries a vulnerability-assertion external reference to the shared Apache Logging Services VDR.
See features.adoc#cyclonedx-sbom for details.
Embedded LICENSE, NOTICE, and DEPENDENCIES
Phase: generate-resources.
The maven-remote-resources-plugin, configured by the ASF Parent POM and its shared resource bundle, contributes three files under the META-INF/ directory of every produced JAR:
META-INF/LICENSE-
the Apache License 2.0 text;
META-INF/NOTICE-
the artifact’s attribution notices;
META-INF/DEPENDENCIES-
a list of the module’s transitive dependencies, grouped by organization and annotated with their licenses.
META-INF/DEPENDENCIES is always generated from the resolved dependency tree.
META-INF/LICENSE and META-INF/NOTICE, on the other hand, are only defaults: a module’s own src/main/resources/META-INF/LICENSE or META-INF/NOTICE takes precedence, so a module that records third-party attributions ships its curated files instead of the generated ones.
Artifact transformations
POM flattening
Phase: process-resources.
The POM you write is not the POM that gets published.
Logging Parent uses CI-friendly versioning, so the project version is the ${revision} property, and a POM still holding an unresolved ${revision} is not consumable by Maven.
The flatten-maven-plugin therefore rewrites the POM into a .flattened-pom.xml, which is the file actually installed and deployed.
The rewrite runs in one of two modes:
- Default (
resolveCiFriendliesOnly) -
Only the CI-friendly properties (
${revision}and friends) are resolved; the rest of the POM, including itsparent, is preserved as-is. - BOM (
bom) -
Activated by
.logging-parent-bom-activator. The POM is reduced to a self-contained Bill of Materials: besides resolving the version, theparent,build,properties, andprofilessections are removed, leaving only the managed dependencies. This keeps consumers of the BOM free of unrelated build configuration.A BOM must therefore not reference a property defined solely in an ancestor POM:
bom-mode interpolation resolves variables from the module’s own POM only, so an inherited property would be left unresolved after flattening.
Optional lifecycle extensions
The following profiles are not activated automatically; you enable them on the command line to add behavior to an otherwise normal build.
-Prelease-
Generates the additional artifacts a release requires: it attaches the
-sourcesJAR and enforces that neither the project version nor any of its dependencies is a SNAPSHOT.Both conditions must hold: the project version itself must be a release version, and every dependency must be a non-SNAPSHOT version.
Apache Logging Service projects do not use the ASF Parent POM’s apache-releaseprofile; thisreleaseprofile, together with thedeployordistributioncommands, replace it. -Pcoverage-
Runs the
jacoco-maven-pluginto collect test coverage during the build and write an HTML report undertarget/site/jacoco. -Dapache.snapshots-
Activates the ASF Parent POM’s
use-apache-snapshotsprofile, adding the Apache snapshots repository. It lets you build only some modules of a project and resolve the rest from the regularly published SNAPSHOT artifacts, instead of building every upstream module locally.
Additional commands
A few profiles are not lifecycle extensions but commands: each carries a defaultGoal, so enabling the profile without naming a phase runs a single task and nothing else.
They are normally invoked by the reusable deployment workflows, but can also be run by hand.
./mvnw -Pchangelog-release-
Moves the pending changelog entries from
src/changelog/.<major>.x.x/into the released version’s directory and regenerates the release notes. ./mvnw -Pdistribution-
Builds the source (
src.zip) and binary (bin.zip) distribution archives from the Git-tracked files. Requires theattachmentFilepathPatternandattachmentCountproperties and a priorpackage. ./mvnw -Pdeploy-
Signs the artifacts and deploys them to the Apache Nexus staging repository via the
nexus-staging-maven-plugin(skipping tests, SpotBugs, and Spotless).